0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-06-30 02:31:10 +00:00

feat(file): add overwrite_unmanaged attribute to virtual_environment_download_file resource (#1064)

* feat(file): add `overwrite_unmanaged` attribute to `virtual_environment_download_file` resource
* misc(ci): add a check for uncommitted generated docs
* misc(ci): better dependency cache

Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
Pavel Boldyrev 2024-02-25 21:33:17 -05:00 committed by GitHub
parent 2ebe46810e
commit c64fcd2948
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 273 additions and 178 deletions

View File

@ -34,6 +34,9 @@ jobs:
if: steps.filter.outputs.go == 'true'
with:
go-version-file: "go.mod"
cache-dependency-path: |
go.sum
tools/go.sum
- name: Lint code
if: steps.filter.outputs.go == 'true'

View File

@ -29,6 +29,9 @@ jobs:
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
cache-dependency-path: |
go.sum
tools/go.sum
- name: Get dependencies
if: steps.filter.outputs.go == 'true'
@ -60,6 +63,9 @@ jobs:
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
cache-dependency-path: |
go.sum
tools/go.sum
- name: Get dependencies
if: steps.filter.outputs.go == 'true'
@ -69,3 +75,6 @@ jobs:
if: steps.filter.outputs.go == 'true'
timeout-minutes: 10
run: go test -v -cover ./...
- name: Check for uncommitted changes in generated docs
run: make docs && git diff --exit-code

View File

@ -41,7 +41,7 @@ resource "proxmox_virtual_environment_download_file" "centos_cloud_image" {
content_type = "iso"
datastore_id = "local"
node_name = "pve"
url = "https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-20231113.0.x86_64.qcow2"
url = "https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-latest.x86_64.qcow2"
file_name = "centos8.img"
}
```
@ -76,7 +76,6 @@ resource "proxmox_virtual_environment_download_file" "ubuntu_cloud_image" {
datastore_id = "local"
node_name = "pve"
url = "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img"
}
```

View File

@ -82,6 +82,7 @@ resource "proxmox_virtual_environment_download_file" "latest_ubuntu_22_jammy_lxc
- `decompression_algorithm` (String) Decompress the downloaded file using the specified compression algorithm. Must be one of `gz` | `lzo` | `zst`.
- `file_name` (String) The file name. If not provided, it is calculated using `url`. PVE will raise 'wrong file extension' error for some popular extensions file `.raw` or `.qcow2`. Workaround is to use e.g. `.img` instead.
- `overwrite` (Boolean) If `true` and size of uploaded file is different, than size from `url` Content-Length header, file will be downloaded again. If `false`, there will be no checks.
- `overwrite_unmanaged` (Boolean) If `true` and a file with the same name already exists in the datastore, it will be deleted and the new file will be downloaded. If `false` and the file already exists, an error will be returned.
- `upload_timeout` (Number) The file download timeout seconds. Default is 600 (10min).
- `verify` (Boolean) By default `true`. If `false`, no SSL/TLS certificates will be verified.

View File

@ -1,20 +1,22 @@
## Debian and ubuntu image download
resource "proxmox_virtual_environment_download_file" "release_20231211_ubuntu_22_jammy_lxc_img" {
content_type = "vztmpl"
datastore_id = "local"
node_name = "pve"
url = "https://cloud-images.ubuntu.com/releases/22.04/release-20231211/ubuntu-22.04-server-cloudimg-amd64-root.tar.xz"
checksum = "c9997dcfea5d826fd04871f960c513665f2e87dd7450bba99f68a97e60e4586e"
checksum_algorithm = "sha256"
upload_timeout = 4444
content_type = "vztmpl"
datastore_id = "local"
node_name = "pve"
url = "https://cloud-images.ubuntu.com/releases/22.04/release-20231211/ubuntu-22.04-server-cloudimg-amd64-root.tar.xz"
checksum = "c9997dcfea5d826fd04871f960c513665f2e87dd7450bba99f68a97e60e4586e"
checksum_algorithm = "sha256"
upload_timeout = 4444
overwrite_unmanaged = true
}
resource "proxmox_virtual_environment_download_file" "latest_debian_12_bookworm_qcow2_img" {
content_type = "iso"
datastore_id = "local"
file_name = "debian-12-generic-amd64.img"
node_name = "pve"
url = "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2"
overwrite = true
content_type = "iso"
datastore_id = "local"
file_name = "debian-12-generic-amd64.img"
node_name = "pve"
url = "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2"
overwrite = true
overwrite_unmanaged = true
}

View File

@ -13,7 +13,6 @@ import (
"strconv"
"strings"
"github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
@ -26,6 +25,8 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/storage"
@ -33,9 +34,9 @@ import (
)
var (
_ resource.Resource = &downloadFileResource{}
_ resource.ResourceWithConfigure = &downloadFileResource{}
httpRe = regexp.MustCompile(`https?://.*`)
_ resource.Resource = &downloadFileResource{}
_ resource.ResourceWithConfigure = &downloadFileResource{}
httpRegex = regexp.MustCompile(`https?://.*`)
)
func sizeRequiresReplace() planmodifier.Int64 {
@ -54,7 +55,7 @@ func (r sizeRequiresReplaceModifier) PlanModifyInt64(
return
}
// // Do not replace on resource destroy.
// Do not replace on resource destroy.
if req.Plan.Raw.IsNull() {
return
}
@ -157,9 +158,10 @@ type downloadFileModel struct {
ChecksumAlgorithm types.String `tfsdk:"checksum_algorithm"`
Verify types.Bool `tfsdk:"verify"`
Overwrite types.Bool `tfsdk:"overwrite"`
OverwriteUnmanaged types.Bool `tfsdk:"overwrite_unmanaged"`
}
// NewDownloadFileResource manages files downloaded using proxmomx API.
// NewDownloadFileResource manages files downloaded using Proxmox API.
func NewDownloadFileResource() resource.Resource {
return &downloadFileResource{}
}
@ -247,7 +249,7 @@ func (r *downloadFileResource) Schema(
Description: "The URL to download the file from. Format `https?://.*`.",
Required: true,
Validators: []validator.String{
stringvalidator.RegexMatches(httpRe, "Must match http url regex"),
stringvalidator.RegexMatches(httpRegex, "Must match http url regex"),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
@ -311,6 +313,14 @@ func (r *downloadFileResource) Schema(
Computed: true,
Default: booldefault.StaticBool(true),
},
"overwrite_unmanaged": schema.BoolAttribute{
Description: "If `true` and a file with the same name already exists in the datastore, " +
"it will be deleted and the new file will be downloaded. If `false` and the file already exists, " +
"an error will be returned.",
Optional: true,
Computed: true,
Default: booldefault.StaticBool(false),
},
},
}
}
@ -390,24 +400,36 @@ func (r *downloadFileResource) Create(
plan.UploadTimeout.ValueInt64(),
)
if isErrFileAlreadyExists(err) && plan.OverwriteUnmanaged.ValueBool() {
fileID := plan.Content.ValueString() + "/" + plan.FileName.ValueString()
err = storageClient.DeleteDatastoreFile(ctx, fileID)
if err != nil {
resp.Diagnostics.AddError("Error deleting file from datastore",
fmt.Sprintf("Could not delete file '%s', unexpected error: %s", fileID, err.Error()),
)
}
err = storageClient.DownloadFileByURL(
ctx,
&downloadFileReq,
plan.UploadTimeout.ValueInt64(),
)
}
if err != nil {
if strings.Contains(err.Error(), "refusing to override existing file") {
if isErrFileAlreadyExists(err) {
resp.Diagnostics.AddError(
"File already exists in a datastore, it was created outside of Terraform "+
"File already exists in the datastore, it was created outside of Terraform "+
"or is managed by another resource.",
fmt.Sprintf(
"File already exists in a datastore: `%s`, "+
"error: %s",
plan.FileName.ValueString(),
err.Error(),
fmt.Sprintf("File already exists in the datastore: '%s', error: %s",
plan.FileName.ValueString(), err.Error(),
),
)
} else {
resp.Diagnostics.AddError(
"Error creating Download File interface",
fmt.Sprintf(
"Could not DownloadFileByURL: `%s`, "+
"unexpected error: %s",
"Error downloading file from url",
fmt.Sprintf("Could not download file '%s', unexpected error: %s",
plan.FileName.ValueString(),
err.Error(),
),
@ -607,3 +629,11 @@ func (r *downloadFileResource) Delete(
}
}
}
func isErrFileAlreadyExists(err error) bool {
if err == nil {
return false
}
return strings.Contains(err.Error(), "refusing to override existing file")
}

View File

@ -12,122 +12,164 @@ import (
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/stretchr/testify/require"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/storage"
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
)
const (
accTestDownloadIsoFileName = "proxmox_virtual_environment_download_file.iso_image"
accTestDownloadQcow2FileName = "proxmox_virtual_environment_download_file.qcow2_image"
fakeFileISO = "https://cdn.githubraw.com/rafsaf/a4b19ea5e3485f8da6ca4acf46d09650/raw/d340ec3ddcef9b907ede02f64b5d3f694da5d081/fake_file.iso"
fakeFileQCOW2 = "https://cdn.githubraw.com/rafsaf/036eece601975a3ad632a77fc2809046/raw/10500012fca9b4425b50de67a7258a12cba0c076/fake_file.qcow2"
)
//nolint:paralleltest
func TestAccResourceDownloadFile(t *testing.T) {
tests := []struct {
name string
steps []resource.TestStep
}{
{"download iso file", []resource.TestStep{{
Config: fmt.Sprintf(`
resource "proxmox_virtual_environment_download_file" "iso_image" {
content_type = "iso"
node_name = "%s"
datastore_id = "%s"
url = "%s"
}
`, accTestNodeName, accTestStorageName, fakeFileISO),
Check: resource.ComposeTestCheckFunc(
testResourceAttributes("proxmox_virtual_environment_download_file.iso_image", map[string]string{
"id": "local:iso/fake_file.iso",
"node_name": accTestNodeName,
"datastore_id": accTestStorageName,
"url": fakeFileISO,
"file_name": "fake_file.iso",
"upload_timeout": "600",
"size": "3",
"verify": "true",
}),
testNoResourceAttributes("proxmox_virtual_environment_download_file.iso_image", []string{
"checksum",
"checksum_algorithm",
"decompression_algorithm",
}),
),
}}},
{"download qcow2 file", []resource.TestStep{{
Config: fmt.Sprintf(`
resource "proxmox_virtual_environment_download_file" "qcow2_image" {
content_type = "iso"
node_name = "%s"
datastore_id = "%s"
file_name = "fake_qcow2_file.img"
url = "%s"
checksum = "688787d8ff144c502c7f5cffaafe2cc588d86079f9de88304c26b0cb99ce91c6"
checksum_algorithm = "sha256"
}
`, accTestNodeName, accTestStorageName, fakeFileQCOW2),
Check: resource.ComposeTestCheckFunc(
testResourceAttributes("proxmox_virtual_environment_download_file.qcow2_image", map[string]string{
"id": "local:iso/fake_qcow2_file.img",
"content_type": "iso",
"node_name": accTestNodeName,
"datastore_id": accTestStorageName,
"url": fakeFileQCOW2,
"file_name": "fake_qcow2_file.img",
"upload_timeout": "600",
"size": "3",
"verify": "true",
"checksum": "688787d8ff144c502c7f5cffaafe2cc588d86079f9de88304c26b0cb99ce91c6",
"checksum_algorithm": "sha256",
}),
testNoResourceAttributes("proxmox_virtual_environment_download_file.qcow2_image", []string{
"decompression_algorithm",
}),
),
}}},
{"update file", []resource.TestStep{{
Config: fmt.Sprintf(`
resource "proxmox_virtual_environment_download_file" "iso_image" {
content_type = "iso"
node_name = "%s"
datastore_id = "%s"
file_name = "fake_iso_file.img"
url = "%s"
upload_timeout = 10000
}
`, accTestNodeName, accTestStorageName, fakeFileISO),
Check: resource.ComposeTestCheckFunc(
testResourceAttributes("proxmox_virtual_environment_download_file.iso_image", map[string]string{
"id": "local:iso/fake_iso_file.img",
"content_type": "iso",
"node_name": accTestNodeName,
"datastore_id": accTestStorageName,
"url": fakeFileISO,
"file_name": "fake_iso_file.img",
"upload_timeout": "10000",
"size": "3",
"verify": "true",
}),
testNoResourceAttributes("proxmox_virtual_environment_download_file.iso_image", []string{
"checksum",
"checksum_algorithm",
"decompression_algorithm",
}),
),
}}},
{"override unmanaged file", []resource.TestStep{{
PreConfig: func() {
err := getNodeStorageClient().DownloadFileByURL(context.Background(), &storage.DownloadURLPostRequestBody{
Content: types.StrPtr("iso"),
FileName: types.StrPtr("fake_file.iso"),
Node: types.StrPtr(accTestNodeName),
Storage: types.StrPtr(accTestStorageName),
URL: types.StrPtr(fakeFileISO),
}, 600)
require.NoError(t, err)
t.Cleanup(func() {
err := getNodeStorageClient().DeleteDatastoreFile(context.Background(), "iso/fake_file.iso")
require.NoError(t, err)
})
},
Config: fmt.Sprintf(`
resource "proxmox_virtual_environment_download_file" "iso_image" {
content_type = "iso"
node_name = "%s"
datastore_id = "%s"
url = "%s"
overwrite_unmanaged = true
}
`, accTestNodeName, accTestStorageName, fakeFileISO),
Check: resource.ComposeTestCheckFunc(
testResourceAttributes("proxmox_virtual_environment_download_file.iso_image", map[string]string{
"id": "local:iso/fake_file.iso",
"content_type": "iso",
"node_name": accTestNodeName,
"datastore_id": accTestStorageName,
"url": fakeFileISO,
"file_name": "fake_file.iso",
"size": "3",
"verify": "true",
}),
testNoResourceAttributes("proxmox_virtual_environment_download_file.iso_image", []string{
"checksum",
"checksum_algorithm",
"decompression_algorithm",
}),
),
}}},
}
accProviders := testAccMuxProviders(context.Background(), t)
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: accProviders,
Steps: []resource.TestStep{
// Create and Read testing
{
Config: testAccResourceDownloadIsoFileCreatedConfig(),
Check: testAccResourceDownloadIsoFileCreatedCheck(),
},
{
Config: testAccResourceDownloadQcow2FileCreatedConfig(),
Check: testAccResourceDownloadQcow2FileCreatedCheck(),
},
// Update testing
{
Config: testAccResourceDownloadIsoFileUpdatedConfig(),
Check: testAccResourceDownloadIsoFileUpdatedCheck(),
},
},
})
}
func testAccResourceDownloadIsoFileCreatedConfig() string {
return fmt.Sprintf(`
resource "proxmox_virtual_environment_download_file" "iso_image" {
content_type = "iso"
node_name = "%s"
datastore_id = "%s"
url = "https://cdn.githubraw.com/rafsaf/a4b19ea5e3485f8da6ca4acf46d09650/raw/d340ec3ddcef9b907ede02f64b5d3f694da5d081/fake_file.iso"
}
`, accTestNodeName, accTestStorageName)
}
func testAccResourceDownloadQcow2FileCreatedConfig() string {
return fmt.Sprintf(`
resource "proxmox_virtual_environment_download_file" "qcow2_image" {
content_type = "iso"
node_name = "%s"
datastore_id = "%s"
file_name = "fake_qcow2_file.img"
url = "https://cdn.githubraw.com/rafsaf/036eece601975a3ad632a77fc2809046/raw/10500012fca9b4425b50de67a7258a12cba0c076/fake_file.qcow2"
checksum = "688787d8ff144c502c7f5cffaafe2cc588d86079f9de88304c26b0cb99ce91c6"
checksum_algorithm = "sha256"
}
`, accTestNodeName, accTestStorageName)
}
func testAccResourceDownloadIsoFileCreatedCheck() resource.TestCheckFunc {
return resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "id", "local:iso/fake_file.iso"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "node_name", accTestNodeName),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "datastore_id", accTestStorageName),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "url", "https://cdn.githubraw.com/rafsaf/a4b19ea5e3485f8da6ca4acf46d09650/raw/d340ec3ddcef9b907ede02f64b5d3f694da5d081/fake_file.iso"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "file_name", "fake_file.iso"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "upload_timeout", "600"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "size", "3"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "verify", "true"),
resource.TestCheckNoResourceAttr(accTestDownloadIsoFileName, "checksum"),
resource.TestCheckNoResourceAttr(accTestDownloadIsoFileName, "checksum_algorithm"),
resource.TestCheckNoResourceAttr(accTestDownloadIsoFileName, "decompression_algorithm"),
)
}
func testAccResourceDownloadQcow2FileCreatedCheck() resource.TestCheckFunc {
return resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "id", "local:iso/fake_qcow2_file.img"),
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "content_type", "iso"),
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "node_name", accTestNodeName),
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "datastore_id", accTestStorageName),
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "url", "https://cdn.githubraw.com/rafsaf/036eece601975a3ad632a77fc2809046/raw/10500012fca9b4425b50de67a7258a12cba0c076/fake_file.qcow2"),
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "file_name", "fake_qcow2_file.img"),
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "upload_timeout", "600"),
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "size", "3"),
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "verify", "true"),
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "checksum", "688787d8ff144c502c7f5cffaafe2cc588d86079f9de88304c26b0cb99ce91c6"),
resource.TestCheckResourceAttr(accTestDownloadQcow2FileName, "checksum_algorithm", "sha256"),
resource.TestCheckNoResourceAttr(accTestDownloadQcow2FileName, "decompression_algorithm"),
)
}
func testAccResourceDownloadIsoFileUpdatedConfig() string {
return fmt.Sprintf(`
resource "proxmox_virtual_environment_download_file" "iso_image" {
content_type = "iso"
node_name = "%s"
datastore_id = "%s"
file_name = "fake_iso_file.img"
url = "https://cdn.githubraw.com/rafsaf/a4b19ea5e3485f8da6ca4acf46d09650/raw/d340ec3ddcef9b907ede02f64b5d3f694da5d081/fake_file.iso"
upload_timeout = 10000
}
`, accTestNodeName, accTestStorageName)
}
func testAccResourceDownloadIsoFileUpdatedCheck() resource.TestCheckFunc {
return resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "id", "local:iso/fake_iso_file.img"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "content_type", "iso"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "node_name", accTestNodeName),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "datastore_id", accTestStorageName),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "url", "https://cdn.githubraw.com/rafsaf/a4b19ea5e3485f8da6ca4acf46d09650/raw/d340ec3ddcef9b907ede02f64b5d3f694da5d081/fake_file.iso"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "file_name", "fake_iso_file.img"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "upload_timeout", "10000"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "size", "3"),
resource.TestCheckResourceAttr(accTestDownloadIsoFileName, "verify", "true"),
resource.TestCheckNoResourceAttr(accTestDownloadIsoFileName, "checksum"),
resource.TestCheckNoResourceAttr(accTestDownloadIsoFileName, "checksum_algorithm"),
resource.TestCheckNoResourceAttr(accTestDownloadIsoFileName, "decompression_algorithm"),
)
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: accProviders,
Steps: tt.steps,
})
})
}
}

View File

@ -85,12 +85,12 @@ func TestAccResourceFile(t *testing.T) {
Config: testAccResourceFileMissingSourceConfig(),
ExpectError: regexp.MustCompile("missing argument"),
},
// Do not allow to overwrite the a file
// Do not allow to overwrite the file
{
Config: testAccResourceFileCreatedConfig(snippetFile2.Name(), "overwrite = false"),
ExpectError: regexp.MustCompile("already exists"),
},
// Allow to overwrite the a file by default
// Allow to overwrite the file by default
{
Config: testAccResourceFileCreatedConfig(snippetFile2.Name()),
Check: testAccResourceFileCreatedCheck("snippets", snippetFile2.Name()),

View File

@ -8,12 +8,9 @@ package tests
import (
"context"
"fmt"
"regexp"
"testing"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func TestAccResourceVM(t *testing.T) {
@ -343,24 +340,3 @@ func TestAccResourceVMDisks(t *testing.T) {
})
}
}
func testResourceAttributes(res string, attrs map[string]string) resource.TestCheckFunc {
return func(s *terraform.State) error {
for k, v := range attrs {
if err := resource.TestCheckResourceAttrWith(res, k, func(got string) error {
match, err := regexp.Match(v, []byte(got)) //nolint:mirror
if err != nil {
return fmt.Errorf("error matching '%s': %w", v, err)
}
if !match {
return fmt.Errorf("expected '%s' to match '%s'", got, v)
}
return nil
})(s); err != nil {
return err
}
}
return nil
}
}

View File

@ -9,6 +9,7 @@ package tests
import (
"context"
"fmt"
"regexp"
"sync"
"testing"
@ -17,7 +18,9 @@ import (
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/hashicorp/terraform-plugin-mux/tf5to6server"
"github.com/hashicorp/terraform-plugin-mux/tf6muxserver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/stretchr/testify/require"
"github.com/bpg/terraform-provider-proxmox/fwprovider"
@ -113,3 +116,36 @@ func getNodeStorageClient() *storage.Client {
nodesClient := getNodesClient()
return &storage.Client{Client: nodesClient, StorageName: accTestStorageName}
}
func testResourceAttributes(res string, attrs map[string]string) resource.TestCheckFunc {
return func(s *terraform.State) error {
for k, v := range attrs {
if err := resource.TestCheckResourceAttrWith(res, k, func(got string) error {
match, err := regexp.Match(v, []byte(got)) //nolint:mirror
if err != nil {
return fmt.Errorf("error matching '%s': %w", v, err)
}
if !match {
return fmt.Errorf("expected '%s' to match '%s'", got, v)
}
return nil
})(s); err != nil {
return err
}
}
return nil
}
}
func testNoResourceAttributes(res string, attrs []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, k := range attrs {
if err := resource.TestCheckNoResourceAttr(res, k)(s); err != nil {
return err
}
}
return nil
}
}

View File

@ -1,8 +1,7 @@
---
layout: page
title: Create a VM from a Cloud Image
parent: Guides
subcategory: Virtual Environment
page_title: "Create a VM from a Cloud Image"
subcategory: Guides
description: |-
This guide explains how to create a VM from a cloud image.
---

View File

@ -1,8 +1,7 @@
---
layout: page
title: Configure a VM with Cloud-Init
parent: Guides
subcategory: Virtual Environment
page_title: "Configure a VM with Cloud-Init"
subcategory: Guides
description: |-
This guide explains how to use the Proxmox provider to create and manage virtual machines using cloud-init.
---

View File

@ -1,8 +1,7 @@
---
layout: page
title: Setup a VM with Proxmox
parent: Guides
subcategory: Virtual Environment
page_title: "Setup a VM with Proxmox"
subcategory: Guides
description: |-
This guide will help you setup a proxmox node in VM using virt-manager for a job.
---
@ -93,4 +92,4 @@ Goal is to have a proxmox node in VM using <https://virt-manager.org/> for a job
10. Now you can run `make example`.
11. If you see error with proxmox_virtual_environment_file: the datastore "local" does not support content type "snippets"; supported content types are: [backup iso vztmpl], you need to enable them, see <https://registry.terraform.io/providers/bpg/proxmox/latest/docs/resources/virtual_environment_file#snippets>.
11. If you see error with proxmox_virtual_environment_file: the datastore "local" does not support content type "snippets"; supported content types are: `[backup, iso, vztmpl]`, you need to enable them, see <https://registry.terraform.io/providers/bpg/proxmox/latest/docs/resources/virtual_environment_file#snippets>.