mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-06-29 18:21:10 +00:00
feat(provider): reliable sequential and random vm_id
generation (#1557)
Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
parent
55bacffc38
commit
72f7cb81a8
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
@ -7,5 +7,6 @@
|
||||
"hashicorp.terraform",
|
||||
"joshbolduc.commitlint",
|
||||
"PKief.material-icon-theme",
|
||||
"psioniq.psi-header"
|
||||
]
|
||||
}
|
||||
|
29
.vscode/settings.json
vendored
29
.vscode/settings.json
vendored
@ -1,7 +1,7 @@
|
||||
{
|
||||
"editor.bracketPairColorization.enabled": true,
|
||||
"editor.guides.bracketPairs": true,
|
||||
"editor.guides.bracketPairsHorizontal": true,
|
||||
"editor.guides.bracketPairs": false,
|
||||
"editor.guides.bracketPairsHorizontal": false,
|
||||
"editor.guides.highlightActiveBracketPair": true,
|
||||
"editor.rulers": [
|
||||
100
|
||||
@ -26,12 +26,14 @@
|
||||
"cputype",
|
||||
"cpuunits",
|
||||
"customdiff",
|
||||
"Datasource",
|
||||
"datasource",
|
||||
"datasources",
|
||||
"deepcode",
|
||||
"directsync",
|
||||
"efidisk",
|
||||
"efidisks",
|
||||
"FSTRIM",
|
||||
"fwprovider",
|
||||
"gocritic",
|
||||
"gosimple",
|
||||
"hookscript",
|
||||
@ -110,4 +112,25 @@
|
||||
"version": "include",
|
||||
"datasource": "database",
|
||||
},
|
||||
"psi-header.config": {
|
||||
"forceToTop": true,
|
||||
"blankLinesAfter": 1,
|
||||
"license": "Apache-2.0",
|
||||
},
|
||||
"psi-header.changes-tracking": {
|
||||
"include": ["go"],
|
||||
"isActive": true,
|
||||
"enforceHeader": true,
|
||||
},
|
||||
"psi-header.templates": [
|
||||
{
|
||||
"language": "*",
|
||||
"template": [
|
||||
"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/.",
|
||||
],
|
||||
},
|
||||
],
|
||||
"makefile.configureOnOpen": false
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ When using a non-root user for the SSH connection, the user **must** have the `s
|
||||
|
||||
~> The `root` user on the Proxmox node must be configured with `bash` as the default shell.
|
||||
|
||||
You can configure the `sudo` privilege for the user via the command line on the Proxmox host.
|
||||
You can configure the `sudo` privilege for the user via the command line on the Proxmox host.
|
||||
In the example below, we create a user `terraform` and assign the `sudo` privilege to it. Run the following commands on the Proxmox node in the root shell:
|
||||
|
||||
- Create a new system user:
|
||||
@ -257,11 +257,12 @@ In the example below, we create a user `terraform` and assign the `sudo` privile
|
||||
terraform ALL=(root) NOPASSWD: /usr/bin/tee /var/lib/vz/*
|
||||
```
|
||||
|
||||
If you're using a different datastore for snippets, not the default `local`, you should add the datastore's mount point to the sudoers file as well, for example:
|
||||
If you're using a different datastore for snippets, not the default `local`, you should add the datastore's mount point to the sudoers file as well, for example:
|
||||
|
||||
```text
|
||||
terraform ALL=(root) NOPASSWD: /usr/bin/tee /mnt/pve/cephfs/*
|
||||
```
|
||||
|
||||
You can find the mount point of the datastore by running `pvesh get /storage/<name>` on the Proxmox node.
|
||||
|
||||
- Copy your SSH public key to the `~/.ssh/authorized_keys` file of the `terraform` user on the target node.
|
||||
@ -388,6 +389,14 @@ The workaround is to use password authentication for those operations.
|
||||
|
||||
-> You can also configure additional Proxmox users and roles using [`virtual_environment_user`](https://registry.terraform.io/providers/bpg/proxmox/latest/docs/data-sources/virtual_environment_user) and [`virtual_environment_role`](https://registry.terraform.io/providers/bpg/proxmox/latest/docs/data-sources/virtual_environment_role) resources of the provider.
|
||||
|
||||
## VM and Container ID Assignment
|
||||
|
||||
When creating VMs and Containers, you can specify the optional `vm_id` attribute to set the ID of the VM or Container. However, the ID is a mandatory attribute in the Proxmox API and must be unique within the cluster. If the `vm_id` attribute is not specified, the provider will generate a unique ID and assign it to the resource.
|
||||
|
||||
The Proxmox API provides a helper function to retrieve the “next available” unique ID in the cluster, but there is no option to reserve an ID before a resource is created. Instead, the provider uses a file-based locking technique to reserve retrieved sequential IDs and prevent duplicates. However, conflicts cannot be fully avoided, especially when multiple resources are created simultaneously by different provider instances.
|
||||
|
||||
To mitigate this issue, you can set the `random_vm_ids` attribute to `true` in the `provider` block. This will generate a random ID for each VM or Container when the `vm_id` attribute is not specified. The generated ID is checked for uniqueness through the Proxmox API before resource creation, significantly reducing the risk of conflicts.
|
||||
|
||||
## Temporary Directory
|
||||
|
||||
Using `proxmox_virtual_environment_file` with `.iso` files or disk images can require large amount of space in the temporary directory of the computer running terraform.
|
||||
@ -426,3 +435,6 @@ In addition to [generic provider arguments](https://www.terraform.io/docs/config
|
||||
- `address` - (Required) The FQDN/IP address of the node.
|
||||
- `port` - (Optional) SSH port of the node. Defaults to 22.
|
||||
- `tmp_dir` - (Optional) Use custom temporary directory. (can also be sourced from `PROXMOX_VE_TMPDIR`)
|
||||
- `random_vm_ids` - (Optional) Use random VM ID for VMs and Containers when `vm_id` attribute is not specified. Defaults to `false`.
|
||||
- `random_vm_id_start` - (Optional) The start of the range for random VM IDs. Defaults to `10000`.
|
||||
- `random_vm_id_end` - (Optional) The end of the range for random VM IDs. Defaults to `99999`.
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/helpers/ptr"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
@ -108,19 +109,17 @@ func (r *aclResource) Configure(_ context.Context, req resource.ConfigureRequest
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
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),
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = client
|
||||
r.client = cfg.Client
|
||||
}
|
||||
|
||||
func (r *aclResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/access"
|
||||
@ -121,18 +122,19 @@ func (r *userTokenResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = client
|
||||
r.client = cfg.Client
|
||||
|
||||
r.client = cfg.Client
|
||||
}
|
||||
|
||||
func (r *userTokenResource) Metadata(
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme/account"
|
||||
)
|
||||
|
||||
@ -131,18 +131,17 @@ func (d *acmeAccountDatasource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().ACME().Account()
|
||||
d.client = cfg.Client.Cluster().ACME().Account()
|
||||
}
|
||||
|
||||
// Read retrieves the ACME account information.
|
||||
@ -157,7 +156,7 @@ func (d *acmeAccountDatasource) Read(ctx context.Context, req datasource.ReadReq
|
||||
|
||||
name := state.Name.ValueString()
|
||||
|
||||
account, err := d.client.Get(ctx, name)
|
||||
accountData, err := d.client.Get(ctx, name)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
fmt.Sprintf("Unable to read ACME account '%s'", name),
|
||||
@ -167,15 +166,15 @@ func (d *acmeAccountDatasource) Read(ctx context.Context, req datasource.ReadReq
|
||||
return
|
||||
}
|
||||
|
||||
contactList := make([]types.String, len(account.Account.Contact))
|
||||
for i, contact := range account.Account.Contact {
|
||||
contactList := make([]types.String, len(accountData.Account.Contact))
|
||||
for i, contact := range accountData.Account.Contact {
|
||||
contactList[i] = types.StringValue(contact)
|
||||
}
|
||||
|
||||
data := &accountDataModel{
|
||||
Contact: contactList,
|
||||
CreatedAt: types.StringValue(account.Account.CreatedAt),
|
||||
Status: types.StringValue(account.Account.Status),
|
||||
CreatedAt: types.StringValue(accountData.Account.CreatedAt),
|
||||
Status: types.StringValue(accountData.Account.Status),
|
||||
}
|
||||
|
||||
accountObject, diags := types.ObjectValueFrom(ctx, data.attrTypes(), data)
|
||||
@ -183,9 +182,9 @@ func (d *acmeAccountDatasource) Read(ctx context.Context, req datasource.ReadReq
|
||||
|
||||
state.Account = accountObject
|
||||
|
||||
state.Directory = types.StringValue(account.Directory)
|
||||
state.Location = types.StringValue(account.Location)
|
||||
state.TOS = types.StringValue(account.TOS)
|
||||
state.Directory = types.StringValue(accountData.Directory)
|
||||
state.Location = types.StringValue(accountData.Location)
|
||||
state.TOS = types.StringValue(accountData.TOS)
|
||||
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme/account"
|
||||
)
|
||||
|
||||
@ -77,18 +77,17 @@ func (d *acmeAccountsDatasource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().ACME().Account()
|
||||
d.client = cfg.Client.Cluster().ACME().Account()
|
||||
}
|
||||
|
||||
// Read fetches the list of ACME Accounts from the Proxmox cluster then converts it to a list of strings.
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme/plugins"
|
||||
)
|
||||
|
||||
@ -102,18 +102,17 @@ func (d *acmePluginDatasource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().ACME().Plugins()
|
||||
d.client = cfg.Client.Cluster().ACME().Plugins()
|
||||
}
|
||||
|
||||
// Read fetches the ACME plugin from the Proxmox cluster.
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme/plugins"
|
||||
)
|
||||
|
||||
@ -110,18 +110,17 @@ func (d *acmePluginsDatasource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().ACME().Plugins()
|
||||
d.client = cfg.Client.Cluster().ACME().Plugins()
|
||||
}
|
||||
|
||||
// Read fetches the list of ACME plugins from the Proxmox cluster.
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme/account"
|
||||
)
|
||||
|
||||
@ -40,7 +40,7 @@ func NewACMEAccountResource() resource.Resource {
|
||||
// acmeAccountResource contains the resource's internal data.
|
||||
type acmeAccountResource struct {
|
||||
// The ACME account API client
|
||||
client account.Client
|
||||
client *account.Client
|
||||
}
|
||||
|
||||
// acmeAccountModel maps the schema data for the ACME account resource.
|
||||
@ -137,16 +137,17 @@ func (r *acmeAccountResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
if ok {
|
||||
r.client = *client.Cluster().ACME().Account()
|
||||
} else {
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = cfg.Client.Cluster().ACME().Account()
|
||||
}
|
||||
|
||||
// Create creates a new ACME account on the Proxmox cluster.
|
||||
|
@ -19,7 +19,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/acme/plugins"
|
||||
)
|
||||
|
||||
@ -36,8 +36,8 @@ func NewACMEPluginResource() resource.Resource {
|
||||
|
||||
// acmePluginResource contains the resource's internal data.
|
||||
type acmePluginResource struct {
|
||||
// The ACME account API client
|
||||
client plugins.Client
|
||||
// The ACME plugin API client
|
||||
client *plugins.Client
|
||||
}
|
||||
|
||||
// Metadata defines the name of the resource.
|
||||
@ -108,16 +108,17 @@ func (r *acmePluginResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
if ok {
|
||||
r.client = *client.Cluster().ACME().Plugins()
|
||||
} else {
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = cfg.Client.Cluster().ACME().Plugins()
|
||||
}
|
||||
|
||||
// Create creates a new ACME plugin on the Proxmox cluster.
|
||||
|
14
fwprovider/config/datasource.go
Normal file
14
fwprovider/config/datasource.go
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* 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 config
|
||||
|
||||
import "github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
|
||||
// DataSource is the global configuration for all datasources.
|
||||
type DataSource struct {
|
||||
Client proxmox.Client
|
||||
}
|
8
fwprovider/config/doc.go
Normal file
8
fwprovider/config/doc.go
Normal 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 config provides the global provider's configuration for all resources and datasources.
|
||||
package config
|
19
fwprovider/config/resource.go
Normal file
19
fwprovider/config/resource.go
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 config
|
||||
|
||||
import (
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster"
|
||||
)
|
||||
|
||||
// Resource is the global configuration for all resources.
|
||||
type Resource struct {
|
||||
Client proxmox.Client
|
||||
|
||||
IDGenerator cluster.IDGenerator
|
||||
}
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
)
|
||||
|
||||
@ -85,19 +86,17 @@ func (d *versionDatasource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client
|
||||
d.client = cfg.Client
|
||||
}
|
||||
|
||||
// Read refreshes the Terraform state with the latest data.
|
||||
|
@ -15,8 +15,8 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
hagroups "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/groups"
|
||||
)
|
||||
|
||||
@ -89,18 +89,17 @@ func (d *haGroupDatasource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().HA().Groups()
|
||||
d.client = cfg.Client.Cluster().HA().Groups()
|
||||
}
|
||||
|
||||
// Read fetches the list of HA groups from the Proxmox cluster then converts it to a list of strings.
|
||||
|
@ -16,8 +16,8 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
hagroups "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/groups"
|
||||
)
|
||||
|
||||
@ -77,18 +77,17 @@ func (d *haGroupsDatasource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().HA().Groups()
|
||||
d.client = cfg.Client.Cluster().HA().Groups()
|
||||
}
|
||||
|
||||
// Read fetches the list of HA groups from the Proxmox cluster then converts it to a list of strings.
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
haresources "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/resources"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
@ -96,16 +96,17 @@ func (d *haResourceDatasource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
if ok {
|
||||
d.client = client.Cluster().HA().Resources()
|
||||
} else {
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = cfg.Client.Cluster().HA().Resources()
|
||||
}
|
||||
|
||||
// Read fetches the specified HA resource.
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
haresources "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/resources"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
@ -92,16 +92,17 @@ func (d *haResourcesDatasource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
if ok {
|
||||
d.client = client.Cluster().HA().Resources()
|
||||
} else {
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = cfg.Client.Cluster().HA().Resources()
|
||||
}
|
||||
|
||||
// Read fetches the list of HA resources from the Proxmox cluster then converts it to a list of strings.
|
||||
|
@ -24,8 +24,8 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
hagroups "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/groups"
|
||||
)
|
||||
|
||||
@ -43,7 +43,7 @@ func NewHAGroupResource() resource.Resource {
|
||||
// hagroupResource contains the resource's internal data.
|
||||
type hagroupResource struct {
|
||||
// The HA groups API client
|
||||
client hagroups.Client
|
||||
client *hagroups.Client
|
||||
}
|
||||
|
||||
// Metadata defines the name of the resource.
|
||||
@ -130,16 +130,17 @@ func (r *hagroupResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
if ok {
|
||||
r.client = *client.Cluster().HA().Groups()
|
||||
} else {
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T",
|
||||
req.ProviderData),
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = cfg.Client.Cluster().HA().Groups()
|
||||
}
|
||||
|
||||
// Create creates a new HA group on the Proxmox cluster.
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
haresources "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/resources"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
|
||||
@ -35,7 +35,7 @@ import (
|
||||
// and the entity name in the API is "ha resource", so...
|
||||
type haResourceResource struct {
|
||||
// The HA resources API client
|
||||
client haresources.Client
|
||||
client *haresources.Client
|
||||
}
|
||||
|
||||
// Ensure the resource implements the expected interfaces.
|
||||
@ -144,15 +144,17 @@ func (r *haResourceResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
if ok {
|
||||
r.client = *client.Cluster().HA().Resources()
|
||||
} else {
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = cfg.Client.Cluster().HA().Resources()
|
||||
}
|
||||
|
||||
// Create creates a new HA resource.
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types/hardwaremapping"
|
||||
)
|
||||
@ -42,17 +42,17 @@ func (d *dataSource) Configure(_ context.Context, req datasource.ConfigureReques
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().HardwareMapping()
|
||||
d.client = cfg.Client.Cluster().HardwareMapping()
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
|
@ -16,9 +16,9 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/hardwaremapping"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
mappings "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types/hardwaremapping"
|
||||
)
|
||||
@ -45,17 +45,17 @@ func (d *pciDataSource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().HardwareMapping()
|
||||
d.client = cfg.Client.Cluster().HardwareMapping()
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
|
@ -16,9 +16,9 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/hardwaremapping"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
mappings "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types/hardwaremapping"
|
||||
)
|
||||
@ -44,17 +44,17 @@ func (d *usbDataSource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client.Cluster().HardwareMapping()
|
||||
d.client = cfg.Client.Cluster().HardwareMapping()
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
|
@ -23,9 +23,9 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/hardwaremapping"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
mappings "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types/hardwaremapping"
|
||||
)
|
||||
@ -40,7 +40,7 @@ var (
|
||||
// pciResource contains the PCI hardware mapping resource's internal data.
|
||||
type pciResource struct {
|
||||
// client is the hardware mapping API client.
|
||||
client mappings.Client
|
||||
client *mappings.Client
|
||||
}
|
||||
|
||||
// read reads information about a PCI hardware mapping from the Proxmox VE API.
|
||||
@ -89,15 +89,17 @@ func (r *pciResource) Configure(_ context.Context, req resource.ConfigureRequest
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = *client.Cluster().HardwareMapping()
|
||||
r.client = cfg.Client.Cluster().HardwareMapping()
|
||||
}
|
||||
|
||||
// Create creates a new PCI hardware mapping.
|
||||
|
@ -22,9 +22,9 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/hardwaremapping"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
mappings "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types/hardwaremapping"
|
||||
)
|
||||
@ -39,7 +39,7 @@ var (
|
||||
// usbResource contains the USB hardware mapping resource's internal data.
|
||||
type usbResource struct {
|
||||
// client is the hardware mapping API client.
|
||||
client mappings.Client
|
||||
client *mappings.Client
|
||||
}
|
||||
|
||||
// read reads information about a USB hardware mapping from the Proxmox VE API.
|
||||
@ -88,16 +88,17 @@ func (r *usbResource) Configure(_ context.Context, req resource.ConfigureRequest
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = *client.Cluster().HardwareMapping()
|
||||
r.client = cfg.Client.Cluster().HardwareMapping()
|
||||
}
|
||||
|
||||
// Create creates a new USB hardware mapping.
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
@ -250,18 +251,17 @@ func (r *linuxBridgeResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = client
|
||||
r.client = cfg.Client
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
@ -223,18 +224,17 @@ func (r *linuxVLANResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = client
|
||||
r.client = cfg.Client
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
)
|
||||
@ -43,18 +44,17 @@ func (d *repositoryDataSource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Data Source Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client
|
||||
d.client = cfg.Client
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/nodes/apt"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
@ -42,18 +43,17 @@ func (d *standardRepositoryDataSource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Data Source Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client
|
||||
d.client = cfg.Client
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
api "github.com/bpg/terraform-provider-proxmox/proxmox/nodes/apt/repositories"
|
||||
@ -105,18 +106,17 @@ func (r *repositoryResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected resource configuration type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = client
|
||||
r.client = cfg.Client
|
||||
}
|
||||
|
||||
// Create modifies the activation state of an existing APT repository, including the addition of standard repositories
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/nodes/apt"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
@ -106,18 +107,17 @@ func (r *standardRepositoryResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected resource configuration type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected config.Resource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r.client = client
|
||||
r.client = cfg.Client
|
||||
}
|
||||
|
||||
// Create adds an APT standard repository to the repository source lists.
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/access"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/acme"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/ha"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/hardwaremapping"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/network"
|
||||
@ -33,6 +34,7 @@ import (
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/vm"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/ssh"
|
||||
"github.com/bpg/terraform-provider-proxmox/utils"
|
||||
@ -85,11 +87,13 @@ type proxmoxProviderModel struct {
|
||||
Port types.Int64 `tfsdk:"port"`
|
||||
} `tfsdk:"node"`
|
||||
} `tfsdk:"ssh"`
|
||||
TmpDir types.String `tfsdk:"tmp_dir"`
|
||||
TmpDir types.String `tfsdk:"tmp_dir"`
|
||||
RandomVMIDs types.Bool `tfsdk:"random_vm_ids"`
|
||||
RandomVMIDStat types.Int64 `tfsdk:"random_vm_id_start"`
|
||||
RandomVMIDEnd types.Int64 `tfsdk:"random_vm_id_end"`
|
||||
}
|
||||
|
||||
func (p *proxmoxProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
|
||||
// resp.TypeName = "proxmox"
|
||||
resp.TypeName = "proxmox_virtual_environment"
|
||||
resp.Version = p.version
|
||||
}
|
||||
@ -140,6 +144,20 @@ func (p *proxmoxProvider) Schema(_ context.Context, _ provider.SchemaRequest, re
|
||||
Optional: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
"random_vm_ids": schema.BoolAttribute{
|
||||
Description: "Whether to generate random VM / Container IDs.",
|
||||
Optional: true,
|
||||
},
|
||||
"random_vm_id_start": schema.Int64Attribute{
|
||||
Description: "The starting number for random VM / Container IDs.",
|
||||
Optional: true,
|
||||
Validators: []validator.Int64{int64validator.Between(100, 999999999)},
|
||||
},
|
||||
"random_vm_id_end": schema.Int64Attribute{
|
||||
Description: "The ending number for random VM / Container IDs.",
|
||||
Optional: true,
|
||||
Validators: []validator.Int64{int64validator.Between(100, 999999999)},
|
||||
},
|
||||
"tmp_dir": schema.StringAttribute{
|
||||
Description: "The alternative temporary directory.",
|
||||
Optional: true,
|
||||
@ -242,8 +260,8 @@ func (p *proxmoxProvider) Configure(
|
||||
tflog.Info(ctx, "Configuring the Proxmox provider...")
|
||||
|
||||
// Retrieve provider data from configuration
|
||||
var config proxmoxProviderModel
|
||||
diags := req.Config.Get(ctx, &config)
|
||||
var cfg proxmoxProviderModel
|
||||
diags := req.Config.Get(ctx, &cfg)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
@ -253,7 +271,7 @@ func (p *proxmoxProvider) Configure(
|
||||
// If practitioner provided a configuration value for any of the
|
||||
// attributes, it must be a known value.
|
||||
|
||||
if config.Endpoint.IsUnknown() {
|
||||
if cfg.Endpoint.IsUnknown() {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
path.Root("endpoint"),
|
||||
"Unknown Proxmox VE API Endpoint",
|
||||
@ -280,36 +298,40 @@ func (p *proxmoxProvider) Configure(
|
||||
username := utils.GetAnyStringEnv("PROXMOX_VE_USERNAME")
|
||||
password := utils.GetAnyStringEnv("PROXMOX_VE_PASSWORD")
|
||||
|
||||
if !config.Endpoint.IsNull() {
|
||||
endpoint = config.Endpoint.ValueString()
|
||||
if !cfg.APIToken.IsNull() {
|
||||
apiToken = cfg.APIToken.ValueString()
|
||||
}
|
||||
|
||||
if !config.Insecure.IsNull() {
|
||||
insecure = config.Insecure.ValueBool()
|
||||
if !cfg.Endpoint.IsNull() {
|
||||
endpoint = cfg.Endpoint.ValueString()
|
||||
}
|
||||
|
||||
if !config.MinTLS.IsNull() {
|
||||
minTLS = config.MinTLS.ValueString()
|
||||
if !cfg.Insecure.IsNull() {
|
||||
insecure = cfg.Insecure.ValueBool()
|
||||
}
|
||||
|
||||
if !config.AuthTicket.IsNull() {
|
||||
authTicket = config.AuthTicket.ValueString()
|
||||
if !cfg.MinTLS.IsNull() {
|
||||
minTLS = cfg.MinTLS.ValueString()
|
||||
}
|
||||
|
||||
if !config.CSRFPreventionToken.IsNull() {
|
||||
csrfPreventionToken = config.CSRFPreventionToken.ValueString()
|
||||
if !cfg.AuthTicket.IsNull() {
|
||||
authTicket = cfg.AuthTicket.ValueString()
|
||||
}
|
||||
|
||||
if !config.APIToken.IsNull() {
|
||||
apiToken = config.APIToken.ValueString()
|
||||
if !cfg.CSRFPreventionToken.IsNull() {
|
||||
csrfPreventionToken = cfg.CSRFPreventionToken.ValueString()
|
||||
}
|
||||
|
||||
if !config.Username.IsNull() {
|
||||
username = config.Username.ValueString()
|
||||
if !cfg.APIToken.IsNull() {
|
||||
apiToken = cfg.APIToken.ValueString()
|
||||
}
|
||||
|
||||
if !config.Password.IsNull() {
|
||||
password = config.Password.ValueString()
|
||||
if !cfg.Username.IsNull() {
|
||||
username = cfg.Username.ValueString()
|
||||
}
|
||||
|
||||
if !cfg.Password.IsNull() {
|
||||
password = cfg.Password.ValueString()
|
||||
}
|
||||
|
||||
if endpoint == "" {
|
||||
@ -371,40 +393,40 @@ func (p *proxmoxProvider) Configure(
|
||||
nodeOverrides := map[string]ssh.ProxmoxNode{}
|
||||
|
||||
//nolint: nestif
|
||||
if len(config.SSH) > 0 {
|
||||
if !config.SSH[0].Username.IsNull() {
|
||||
sshUsername = config.SSH[0].Username.ValueString()
|
||||
if len(cfg.SSH) > 0 {
|
||||
if !cfg.SSH[0].Username.IsNull() {
|
||||
sshUsername = cfg.SSH[0].Username.ValueString()
|
||||
}
|
||||
|
||||
if !config.SSH[0].Password.IsNull() {
|
||||
sshPassword = config.SSH[0].Password.ValueString()
|
||||
if !cfg.SSH[0].Password.IsNull() {
|
||||
sshPassword = cfg.SSH[0].Password.ValueString()
|
||||
}
|
||||
|
||||
if !config.SSH[0].Agent.IsNull() {
|
||||
sshAgent = config.SSH[0].Agent.ValueBool()
|
||||
if !cfg.SSH[0].Agent.IsNull() {
|
||||
sshAgent = cfg.SSH[0].Agent.ValueBool()
|
||||
}
|
||||
|
||||
if !config.SSH[0].AgentSocket.IsNull() {
|
||||
sshAgentSocket = config.SSH[0].AgentSocket.ValueString()
|
||||
if !cfg.SSH[0].AgentSocket.IsNull() {
|
||||
sshAgentSocket = cfg.SSH[0].AgentSocket.ValueString()
|
||||
}
|
||||
|
||||
if !config.SSH[0].PrivateKey.IsNull() {
|
||||
sshPrivateKey = config.SSH[0].PrivateKey.ValueString()
|
||||
if !cfg.SSH[0].PrivateKey.IsNull() {
|
||||
sshPrivateKey = cfg.SSH[0].PrivateKey.ValueString()
|
||||
}
|
||||
|
||||
if !config.SSH[0].Socks5Server.IsNull() {
|
||||
sshSocks5Server = config.SSH[0].Socks5Server.ValueString()
|
||||
if !cfg.SSH[0].Socks5Server.IsNull() {
|
||||
sshSocks5Server = cfg.SSH[0].Socks5Server.ValueString()
|
||||
}
|
||||
|
||||
if !config.SSH[0].Socks5Username.IsNull() {
|
||||
sshSocks5Username = config.SSH[0].Socks5Username.ValueString()
|
||||
if !cfg.SSH[0].Socks5Username.IsNull() {
|
||||
sshSocks5Username = cfg.SSH[0].Socks5Username.ValueString()
|
||||
}
|
||||
|
||||
if !config.SSH[0].Socks5Password.IsNull() {
|
||||
sshSocks5Password = config.SSH[0].Socks5Password.ValueString()
|
||||
if !cfg.SSH[0].Socks5Password.IsNull() {
|
||||
sshSocks5Password = cfg.SSH[0].Socks5Password.ValueString()
|
||||
}
|
||||
|
||||
for _, n := range config.SSH[0].Nodes {
|
||||
for _, n := range cfg.SSH[0].Nodes {
|
||||
nodePort := int32(n.Port.ValueInt64())
|
||||
if nodePort == 0 {
|
||||
nodePort = 22
|
||||
@ -447,14 +469,27 @@ func (p *proxmoxProvider) Configure(
|
||||
// Intentionally use 'PROXMOX_VE_TMPDIR' with 'TMP' instead of 'TEMP', to match os.TempDir's use of $TMPDIR
|
||||
tmpDirOverride := utils.GetAnyStringEnv("PROXMOX_VE_TMPDIR", "PM_VE_TMPDIR")
|
||||
|
||||
if !config.TmpDir.IsNull() {
|
||||
tmpDirOverride = config.TmpDir.ValueString()
|
||||
if !cfg.TmpDir.IsNull() {
|
||||
tmpDirOverride = cfg.TmpDir.ValueString()
|
||||
}
|
||||
|
||||
client := proxmox.NewClient(apiClient, sshClient, tmpDirOverride)
|
||||
|
||||
resp.ResourceData = client
|
||||
resp.DataSourceData = client
|
||||
resp.ResourceData = config.Resource{
|
||||
Client: client,
|
||||
IDGenerator: cluster.NewIDGenerator(
|
||||
client.Cluster(),
|
||||
cluster.IDGeneratorConfig{
|
||||
RandomIDs: cfg.RandomVMIDs.ValueBool(),
|
||||
RandomIDStat: int(cfg.RandomVMIDStat.ValueInt64()),
|
||||
RandomIDEnd: int(cfg.RandomVMIDEnd.ValueInt64()),
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
resp.DataSourceData = config.DataSource{
|
||||
Client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *proxmoxProvider) Resources(_ context.Context) []func() resource.Resource {
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
@ -333,7 +334,7 @@ func (r *downloadFileResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
@ -344,7 +345,7 @@ func (r *downloadFileResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
r.client = client
|
||||
r.client = cfg.Client
|
||||
}
|
||||
|
||||
func (r *downloadFileResource) Create(
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster"
|
||||
@ -697,7 +698,7 @@ func (r *clusterOptionsResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
@ -708,7 +709,7 @@ func (r *clusterOptionsResource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
r.client = client
|
||||
r.client = cfg.Client
|
||||
}
|
||||
|
||||
// Create update must-existing cluster options.
|
||||
|
@ -114,7 +114,6 @@ func TestAccResourceContainer(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_container" "test_container" {
|
||||
node_name = "{{.NodeName}}"
|
||||
vm_id = {{.RandomVMID}}
|
||||
started = false
|
||||
disk {
|
||||
datastore_id = "local-lvm"
|
||||
@ -190,7 +189,6 @@ func TestAccResourceContainer(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_container" "test_container" {
|
||||
node_name = "{{.NodeName}}"
|
||||
vm_id = {{.RandomVMID}}
|
||||
template = true
|
||||
disk {
|
||||
datastore_id = "local-lvm"
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v7"
|
||||
"github.com/hashicorp/terraform-plugin-framework/providerserver"
|
||||
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
|
||||
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
|
||||
@ -81,6 +80,7 @@ provider "proxmox" {
|
||||
port = %s
|
||||
}
|
||||
}
|
||||
//random_vm_ids = true
|
||||
}
|
||||
`, nodeName, nodeAddress, nodePort)
|
||||
|
||||
@ -128,10 +128,6 @@ func (e *Environment) RenderConfig(cfg string) string {
|
||||
tmpl, err := template.New("config").Parse("{{.ProviderConfig}}" + cfg)
|
||||
require.NoError(e.t, err)
|
||||
|
||||
e.templateVars["RandomVMID"] = gofakeit.IntRange(100_000, 999_999)
|
||||
e.templateVars["RandomVMID1"] = gofakeit.IntRange(100_000, 999_999)
|
||||
e.templateVars["RandomVMID2"] = gofakeit.IntRange(100_000, 999_999)
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = tmpl.Execute(&buf, e.templateVars)
|
||||
require.NoError(e.t, err)
|
||||
|
@ -31,7 +31,6 @@ func TestAccResourceVM2CDROM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-cdrom"
|
||||
cdrom = {
|
||||
"ide3" = {}
|
||||
@ -46,7 +45,6 @@ func TestAccResourceVM2CDROM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-cdrom"
|
||||
cdrom = {
|
||||
"ide3" = {},
|
||||
@ -66,7 +64,6 @@ func TestAccResourceVM2CDROM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-cdrom"
|
||||
cdrom = {
|
||||
"scsi2" = {
|
||||
@ -107,7 +104,6 @@ func TestAccResourceVM2CDROM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "template_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID1}}
|
||||
name = "template-cdrom"
|
||||
cdrom = {
|
||||
"ide3" = {
|
||||
@ -117,7 +113,6 @@ func TestAccResourceVM2CDROM(t *testing.T) {
|
||||
}
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID2}}
|
||||
name = "test-cdrom"
|
||||
clone = {
|
||||
id = proxmox_virtual_environment_vm2.template_vm.id
|
||||
@ -132,7 +127,6 @@ func TestAccResourceVM2CDROM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "template_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID1}}
|
||||
name = "template-cdrom"
|
||||
cdrom = {
|
||||
"ide1" = {
|
||||
@ -145,7 +139,6 @@ func TestAccResourceVM2CDROM(t *testing.T) {
|
||||
}
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID2}}
|
||||
name = "test-cpu"
|
||||
clone = {
|
||||
id = proxmox_virtual_environment_vm2.template_vm.id
|
||||
|
@ -29,7 +29,6 @@ func TestAccResourceVM2CPU(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-cpu"
|
||||
}`),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
@ -45,7 +44,6 @@ func TestAccResourceVM2CPU(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-cpu"
|
||||
cpu = {
|
||||
cores = 2
|
||||
@ -69,7 +67,6 @@ func TestAccResourceVM2CPU(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-cpu"
|
||||
cpu = {
|
||||
# affinity = "0-1" only root can set affinity
|
||||
@ -135,7 +132,6 @@ func TestAccResourceVM2CPU(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "template_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID1}}
|
||||
name = "template-cpu"
|
||||
cpu = {
|
||||
cores = 2
|
||||
@ -145,7 +141,6 @@ func TestAccResourceVM2CPU(t *testing.T) {
|
||||
}
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID2}}
|
||||
name = "test-cpu"
|
||||
clone = {
|
||||
id = proxmox_virtual_environment_vm2.template_vm.id
|
||||
@ -163,7 +158,6 @@ func TestAccResourceVM2CPU(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "template_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID1}}
|
||||
name = "template-cpu"
|
||||
cpu = {
|
||||
cores = 2
|
||||
@ -173,7 +167,6 @@ func TestAccResourceVM2CPU(t *testing.T) {
|
||||
}
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID2}}
|
||||
name = "test-cpu"
|
||||
clone = {
|
||||
id = proxmox_virtual_environment_vm2.template_vm.id
|
||||
|
@ -1,3 +1,9 @@
|
||||
/*
|
||||
* 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 vm
|
||||
|
||||
import (
|
||||
@ -7,6 +13,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
)
|
||||
|
||||
@ -45,37 +52,36 @@ func (d *Datasource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.DataSource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
fmt.Sprintf("Expected *proxmox.Client, got: %T", req.ProviderData),
|
||||
"Unexpected DataSource Configure Type",
|
||||
fmt.Sprintf("Expected config.DataSource, got: %T", req.ProviderData),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
d.client = client
|
||||
d.client = cfg.Client
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func (d *Datasource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
||||
var config Model
|
||||
var model Model
|
||||
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &model)...)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
timeout, diags := config.Timeouts.Read(ctx, defaultReadTimeout)
|
||||
timeout, diags := model.Timeouts.Read(ctx, defaultReadTimeout)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
exists := read(ctx, d.client, &config, &resp.Diagnostics)
|
||||
exists := read(ctx, d.client, &model, &resp.Diagnostics)
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
@ -83,12 +89,12 @@ func (d *Datasource) Read(ctx context.Context, req datasource.ReadRequest, resp
|
||||
|
||||
if !exists {
|
||||
tflog.Info(ctx, "VM does not exist, removing from the state", map[string]interface{}{
|
||||
"id": config.ID.ValueInt64(),
|
||||
"id": model.ID.ValueInt64(),
|
||||
})
|
||||
resp.State.RemoveResource(ctx)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, config)...)
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, model)...)
|
||||
}
|
||||
|
@ -21,11 +21,13 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/vm/cdrom"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/vm/cpu"
|
||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/vm/vga"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
|
||||
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||
)
|
||||
@ -48,7 +50,8 @@ var (
|
||||
|
||||
// Resource implements the resource.Resource interface for managing VMs.
|
||||
type Resource struct {
|
||||
client proxmox.Client
|
||||
client proxmox.Client
|
||||
idGenerator cluster.IDGenerator
|
||||
}
|
||||
|
||||
// NewResource creates a new resource for managing VMs.
|
||||
@ -75,8 +78,7 @@ func (r *Resource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(proxmox.Client)
|
||||
|
||||
cfg, ok := req.ProviderData.(config.Resource)
|
||||
if !ok {
|
||||
resp.Diagnostics.AddError(
|
||||
"Unexpected Resource Configure Type",
|
||||
@ -86,7 +88,8 @@ func (r *Resource) Configure(
|
||||
return
|
||||
}
|
||||
|
||||
r.client = client
|
||||
r.client = cfg.Client
|
||||
r.idGenerator = cfg.IDGenerator
|
||||
}
|
||||
|
||||
// Create creates a new VM.
|
||||
@ -106,13 +109,13 @@ func (r *Resource) Create(ctx context.Context, req resource.CreateRequest, resp
|
||||
defer cancel()
|
||||
|
||||
if plan.ID.ValueInt64() == 0 {
|
||||
id, err := r.client.Cluster().GetVMID(ctx)
|
||||
id, err := r.idGenerator.NextID(ctx)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Failed to get VM ID", err.Error())
|
||||
resp.Diagnostics.AddError("Failed to generate VM ID", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
plan.ID = types.Int64Value(int64(*id))
|
||||
plan.ID = types.Int64Value(int64(id))
|
||||
}
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
|
@ -9,6 +9,7 @@
|
||||
package vm_test
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
@ -21,6 +22,9 @@ func TestAccResourceVM(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
te := test.InitEnvironment(t)
|
||||
te.AddTemplateVars(map[string]interface{}{
|
||||
"TestVMID": 100000 + rand.Intn(99999),
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -44,14 +48,13 @@ func TestAccResourceVM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
id = {{.TestVMID}}
|
||||
}`),
|
||||
}}},
|
||||
{"set an invalid VM name", []resource.TestStep{{
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "not a valid DNS name"
|
||||
}`),
|
||||
ExpectError: regexp.MustCompile(`name must be a valid DNS name`),
|
||||
@ -61,7 +64,6 @@ func TestAccResourceVM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-vm"
|
||||
description = "test description"
|
||||
}`),
|
||||
@ -97,7 +99,6 @@ func TestAccResourceVM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-tags"
|
||||
tags = ["tag2", "tag1"]
|
||||
}`),
|
||||
@ -146,7 +147,6 @@ func TestAccResourceVM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
tags = ["", "tag1"]
|
||||
}`),
|
||||
ExpectError: regexp.MustCompile(`string length must be at least 1, got: 0`),
|
||||
@ -155,7 +155,6 @@ func TestAccResourceVM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
tags = [" ", "tag1"]
|
||||
}`),
|
||||
ExpectError: regexp.MustCompile(`must be a non-empty and non-whitespace string`),
|
||||
@ -164,7 +163,6 @@ func TestAccResourceVM(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
description = trimspace(<<-EOT
|
||||
my
|
||||
description
|
||||
@ -203,14 +201,12 @@ func TestAccResourceVM2Clone(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID1}}
|
||||
name = "template"
|
||||
description = "template description"
|
||||
template = true
|
||||
}
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm_clone" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID2}}
|
||||
name = "clone"
|
||||
clone = {
|
||||
id = proxmox_virtual_environment_vm2.test_vm.id
|
||||
@ -234,13 +230,11 @@ func TestAccResourceVM2Clone(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID1}}
|
||||
template = true
|
||||
tags = ["tag1", "tag2"]
|
||||
}
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm_clone" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID2}}
|
||||
clone = {
|
||||
id = proxmox_virtual_environment_vm2.test_vm.id
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ func TestAccResourceVM2VGA(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-vga"
|
||||
}`),
|
||||
Check: test.NoResourceAttributesSet("proxmox_virtual_environment_vm2.test_vm", []string{
|
||||
@ -41,7 +40,6 @@ func TestAccResourceVM2VGA(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-vga"
|
||||
vga = {
|
||||
type = "std"
|
||||
@ -62,7 +60,6 @@ func TestAccResourceVM2VGA(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID}}
|
||||
name = "test-vga"
|
||||
vga = {
|
||||
type = "std"
|
||||
@ -107,7 +104,6 @@ func TestAccResourceVM2VGA(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "template_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID1}}
|
||||
name = "template-vga"
|
||||
vga = {
|
||||
type = "qxl"
|
||||
@ -116,7 +112,6 @@ func TestAccResourceVM2VGA(t *testing.T) {
|
||||
}
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID2}}
|
||||
name = "test-vga"
|
||||
clone = {
|
||||
id = proxmox_virtual_environment_vm2.template_vm.id
|
||||
@ -133,7 +128,6 @@ func TestAccResourceVM2VGA(t *testing.T) {
|
||||
Config: te.RenderConfig(`
|
||||
resource "proxmox_virtual_environment_vm2" "template_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
id = {{.RandomVMID1}}
|
||||
name = "template-vga"
|
||||
vga = {
|
||||
type = "qxl"
|
||||
@ -143,7 +137,6 @@ func TestAccResourceVM2VGA(t *testing.T) {
|
||||
resource "proxmox_virtual_environment_vm2" "test_vm" {
|
||||
node_name = "{{.NodeName}}"
|
||||
name = "test-cpu"
|
||||
id = {{.RandomVMID2}}
|
||||
clone = {
|
||||
id = proxmox_virtual_environment_vm2.template_vm.id
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@ -33,6 +33,7 @@ require (
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
|
||||
@ -62,6 +63,7 @@ require (
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/oklog/run v1.1.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
|
4
go.sum
4
go.sum
@ -36,6 +36,8 @@ github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZt
|
||||
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
||||
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@ -152,6 +154,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
||||
|
@ -11,27 +11,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
)
|
||||
|
||||
const (
|
||||
getVMIDStep = 1
|
||||
)
|
||||
|
||||
// ErrVMDoesNotExist is returned when the VM identifier cannot be found on any cluster node.
|
||||
var ErrVMDoesNotExist = errors.New("unable to find VM identifier on any cluster node")
|
||||
|
||||
var (
|
||||
//nolint:gochecknoglobals
|
||||
getVMIDCounter = -1
|
||||
//nolint:gochecknoglobals
|
||||
getVMIDCounterMutex = &sync.Mutex{}
|
||||
)
|
||||
|
||||
// GetNextID retrieves the next free VM identifier for the cluster.
|
||||
func (c *Client) GetNextID(ctx context.Context, vmID *int) (*int, error) {
|
||||
reqBody := &NextIDRequestBody{
|
||||
@ -52,52 +38,6 @@ func (c *Client) GetNextID(ctx context.Context, vmID *int) (*int, error) {
|
||||
return (*int)(resBody.Data), nil
|
||||
}
|
||||
|
||||
// GetVMID retrieves the next available VM identifier.
|
||||
func (c *Client) GetVMID(ctx context.Context) (*int, error) {
|
||||
getVMIDCounterMutex.Lock()
|
||||
defer getVMIDCounterMutex.Unlock()
|
||||
|
||||
if getVMIDCounter < 0 {
|
||||
nextVMID, err := c.GetNextID(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if nextVMID == nil {
|
||||
return nil, errors.New("unable to retrieve the next available VM identifier")
|
||||
}
|
||||
|
||||
getVMIDCounter = *nextVMID + getVMIDStep
|
||||
|
||||
tflog.Debug(ctx, "next VM identifier", map[string]interface{}{
|
||||
"id": *nextVMID,
|
||||
})
|
||||
|
||||
return nextVMID, nil
|
||||
}
|
||||
|
||||
vmID := getVMIDCounter
|
||||
|
||||
for vmID <= 2147483637 {
|
||||
_, err := c.GetNextID(ctx, &vmID)
|
||||
if err != nil {
|
||||
vmID += getVMIDStep
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
getVMIDCounter = vmID + getVMIDStep
|
||||
|
||||
tflog.Debug(ctx, "next VM identifier", map[string]interface{}{
|
||||
"id": vmID,
|
||||
})
|
||||
|
||||
return &vmID, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("unable to determine the next available VM identifier")
|
||||
}
|
||||
|
||||
// GetClusterResources retrieves current resources for cluster.
|
||||
func (c *Client) GetClusterResources(ctx context.Context, resourceType string) ([]*ResourcesListResponseData, error) {
|
||||
reqBody := &ResourcesListRequestBody{
|
||||
|
136
proxmox/cluster/id_generator.go
Normal file
136
proxmox/cluster/id_generator.go
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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 cluster
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/avast/retry-go/v4"
|
||||
"github.com/rogpeppe/go-internal/lockedfile"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/helpers/ptr"
|
||||
)
|
||||
|
||||
const (
|
||||
idGeneratorLockFile = "terraform-provider-proxmox-id-gen.lock"
|
||||
idGeneratorSequenceFile = "terraform-provider-proxmox-id-gen.seq"
|
||||
)
|
||||
|
||||
// IDGenerator is responsible for generating unique identifiers for VMs and Containers.
|
||||
type IDGenerator struct {
|
||||
client *Client
|
||||
config IDGeneratorConfig
|
||||
}
|
||||
|
||||
// IDGeneratorConfig is the configuration for the IDGenerator.
|
||||
type IDGeneratorConfig struct {
|
||||
RandomIDs bool
|
||||
RandomIDStat int
|
||||
RandomIDEnd int
|
||||
|
||||
lockFName string
|
||||
seqFName string
|
||||
}
|
||||
|
||||
// NewIDGenerator creates a new IDGenerator with the given parameters.
|
||||
func NewIDGenerator(client *Client, config IDGeneratorConfig) IDGenerator {
|
||||
if config.RandomIDStat == 0 {
|
||||
config.RandomIDStat = 10000
|
||||
}
|
||||
|
||||
if config.RandomIDEnd == 0 {
|
||||
config.RandomIDEnd = 99999
|
||||
}
|
||||
|
||||
config.lockFName = filepath.Join(os.TempDir(), idGeneratorLockFile)
|
||||
config.seqFName = filepath.Join(os.TempDir(), idGeneratorSequenceFile)
|
||||
|
||||
unlock, err := lockedfile.MutexAt(config.lockFName).Lock()
|
||||
if err == nil {
|
||||
defer unlock()
|
||||
|
||||
// delete the sequence file if it is older than 10 seconds
|
||||
// this is to prevent the sequence file from growing indefinitely,
|
||||
// while giving some protection against parallel runs of the provider
|
||||
// that might interfere with each other and reset the sequence at the same time
|
||||
stat, err := os.Stat(config.seqFName)
|
||||
if err == nil && time.Since(stat.ModTime()) > 10*time.Second {
|
||||
_ = os.Remove(config.seqFName)
|
||||
}
|
||||
}
|
||||
|
||||
return IDGenerator{client, config}
|
||||
}
|
||||
|
||||
// NextID returns the next available VM identifier.
|
||||
func (g IDGenerator) NextID(ctx context.Context) (int, error) {
|
||||
// lock the ID generator to prevent concurrent access
|
||||
// it should be unlocked only when the new ID is successfully
|
||||
// retrieved (and optionally written to the sequence file)
|
||||
unlock, err := lockedfile.MutexAt(g.config.lockFName).Lock()
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("unable to lock the ID generator: %w", err)
|
||||
}
|
||||
|
||||
defer unlock()
|
||||
|
||||
id, err := retry.DoWithData(func() (*int, error) {
|
||||
var newID *int
|
||||
|
||||
if g.config.RandomIDs {
|
||||
//nolint:gosec
|
||||
newID = ptr.Ptr(rand.Intn(g.config.RandomIDEnd-g.config.RandomIDStat) + g.config.RandomIDStat)
|
||||
} else {
|
||||
newID, err = nextSequentialID(g.config.seqFName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return g.client.GetNextID(ctx, newID)
|
||||
})
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("unable to retrieve the next available VM identifier: %w", err)
|
||||
}
|
||||
|
||||
if !g.config.RandomIDs {
|
||||
var b bytes.Buffer
|
||||
_, _ = fmt.Fprintf(&b, "%d", *id)
|
||||
|
||||
if err := lockedfile.Write(g.config.seqFName, &b, 0o666); err != nil {
|
||||
return -1, fmt.Errorf("unable to write the ID generator file: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return *id, nil
|
||||
}
|
||||
|
||||
func nextSequentialID(seqFName string) (*int, error) {
|
||||
buf, err := lockedfile.Read(seqFName)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return nil, nil //nolint:nilnil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to read the ID generator sequence file: %w", err)
|
||||
}
|
||||
|
||||
id, err := strconv.Atoi(string(buf))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse the ID generator file: %w", err)
|
||||
}
|
||||
|
||||
return ptr.Ptr(id + 1), nil
|
||||
}
|
@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/ssh"
|
||||
)
|
||||
|
||||
@ -20,6 +21,7 @@ type ProviderConfiguration struct {
|
||||
apiClient api.Client
|
||||
sshClient ssh.Client
|
||||
tmpDirOverride string
|
||||
idGenerator cluster.IDGenerator
|
||||
}
|
||||
|
||||
// NewProviderConfiguration creates a new provider configuration.
|
||||
@ -27,12 +29,22 @@ func NewProviderConfiguration(
|
||||
apiClient api.Client,
|
||||
sshClient ssh.Client,
|
||||
tmpDirOverride string,
|
||||
) ProviderConfiguration {
|
||||
return ProviderConfiguration{
|
||||
idCfg cluster.IDGeneratorConfig,
|
||||
) (ProviderConfiguration, error) {
|
||||
cfg := ProviderConfiguration{
|
||||
apiClient: apiClient,
|
||||
sshClient: sshClient,
|
||||
tmpDirOverride: tmpDirOverride,
|
||||
}
|
||||
|
||||
client, err := cfg.GetClient()
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
cfg.idGenerator = cluster.NewIDGenerator(client.Cluster(), idCfg)
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// GetClient returns the Proxmox API client.
|
||||
@ -60,3 +72,8 @@ func (c *ProviderConfiguration) TempDir() string {
|
||||
|
||||
return os.TempDir()
|
||||
}
|
||||
|
||||
// GetIDGenerator returns the IDGenerator.
|
||||
func (c *ProviderConfiguration) GetIDGenerator() cluster.IDGenerator {
|
||||
return c.idGenerator
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
||||
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmox/ssh"
|
||||
"github.com/bpg/terraform-provider-proxmox/proxmoxtf"
|
||||
@ -210,7 +211,24 @@ func providerConfigure(_ context.Context, d *schema.ResourceData) (interface{},
|
||||
tmpDirOverride = v.(string)
|
||||
}
|
||||
|
||||
config := proxmoxtf.NewProviderConfiguration(apiClient, sshClient, tmpDirOverride)
|
||||
idCfg := cluster.IDGeneratorConfig{}
|
||||
|
||||
if v, ok := d.GetOk(mkProviderRandomVMIDs); ok {
|
||||
idCfg.RandomIDs = v.(bool)
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk(mkProviderRandomVMIDStart); ok {
|
||||
idCfg.RandomIDStat = v.(int)
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk(mkProviderRandomVMIDEnd); ok {
|
||||
idCfg.RandomIDEnd = v.(int)
|
||||
}
|
||||
|
||||
config, err := proxmoxtf.NewProviderConfiguration(apiClient, sshClient, tmpDirOverride, idCfg)
|
||||
if err != nil {
|
||||
return nil, diag.Errorf("error creating provider's configuration: %s", err)
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
@ -24,6 +24,9 @@ const (
|
||||
mkProviderPassword = "password"
|
||||
mkProviderUsername = "username"
|
||||
mkProviderTmpDir = "tmp_dir"
|
||||
mkProviderRandomVMIDs = "random_vm_ids"
|
||||
mkProviderRandomVMIDStart = "random_vm_id_start"
|
||||
mkProviderRandomVMIDEnd = "random_vm_id_end"
|
||||
mkProviderSSH = "ssh"
|
||||
mkProviderSSHUsername = "username"
|
||||
mkProviderSSHPassword = "password"
|
||||
@ -240,5 +243,22 @@ func createSchema() map[string]*schema.Schema {
|
||||
Description: "The alternative temporary directory.",
|
||||
ValidateFunc: validation.StringIsNotEmpty,
|
||||
},
|
||||
mkProviderRandomVMIDs: {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Description: "Whether to generate random VM / Container IDs.",
|
||||
},
|
||||
mkProviderRandomVMIDStart: {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Description: "The starting number for random VM / Container IDs.",
|
||||
ValidateFunc: validation.IntBetween(100, 999999999),
|
||||
},
|
||||
mkProviderRandomVMIDEnd: {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Description: "The ending number for random VM / Container IDs.",
|
||||
ValidateFunc: validation.IntBetween(100, 999999999),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -983,12 +983,12 @@ func containerCreateClone(ctx context.Context, d *schema.ResourceData, m interfa
|
||||
vmID := vmIDUntyped.(int)
|
||||
|
||||
if !hasVMID {
|
||||
vmIDNew, err := client.Cluster().GetVMID(ctx)
|
||||
vmIDNew, err := config.GetIDGenerator().NextID(ctx)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
vmID = *vmIDNew
|
||||
vmID = vmIDNew
|
||||
|
||||
err = d.Set(mkVMID, vmID)
|
||||
if err != nil {
|
||||
@ -1696,12 +1696,12 @@ func containerCreateCustom(ctx context.Context, d *schema.ResourceData, m interf
|
||||
vmID := vmIDUntyped.(int)
|
||||
|
||||
if !hasVMID {
|
||||
vmIDNew, err := client.Cluster().GetVMID(ctx)
|
||||
vmIDNew, err := config.GetIDGenerator().NextID(ctx)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
vmID = *vmIDNew
|
||||
vmID = vmIDNew
|
||||
|
||||
err = d.Set(mkVMID, vmID)
|
||||
if err != nil {
|
||||
|
@ -1713,12 +1713,12 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
|
||||
vmID := vmIDUntyped.(int)
|
||||
|
||||
if !hasVMID {
|
||||
vmIDNew, err := client.Cluster().GetVMID(ctx)
|
||||
vmIDNew, err := config.GetIDGenerator().NextID(ctx)
|
||||
if err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
vmID = *vmIDNew
|
||||
vmID = vmIDNew
|
||||
|
||||
err = d.Set(mkVMID, vmID)
|
||||
if err != nil {
|
||||
@ -2509,12 +2509,12 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
|
||||
vmID := vmIDUntyped.(int)
|
||||
|
||||
if !hasVMID {
|
||||
vmIDNew, e := client.Cluster().GetVMID(ctx)
|
||||
vmIDNew, e := config.GetIDGenerator().NextID(ctx)
|
||||
if e != nil {
|
||||
return diag.FromErr(e)
|
||||
}
|
||||
|
||||
vmID = *vmIDNew
|
||||
vmID = vmIDNew
|
||||
e = d.Set(mkVMID, vmID)
|
||||
|
||||
if e != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user