mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-07-05 05:24:01 +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:
parent
2ebe46810e
commit
c64fcd2948
3
.github/workflows/golangci-lint.yml
vendored
3
.github/workflows/golangci-lint.yml
vendored
@ -34,6 +34,9 @@ jobs:
|
|||||||
if: steps.filter.outputs.go == 'true'
|
if: steps.filter.outputs.go == 'true'
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
|
cache-dependency-path: |
|
||||||
|
go.sum
|
||||||
|
tools/go.sum
|
||||||
|
|
||||||
- name: Lint code
|
- name: Lint code
|
||||||
if: steps.filter.outputs.go == 'true'
|
if: steps.filter.outputs.go == 'true'
|
||||||
|
9
.github/workflows/test.yml
vendored
9
.github/workflows/test.yml
vendored
@ -29,6 +29,9 @@ jobs:
|
|||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
|
cache-dependency-path: |
|
||||||
|
go.sum
|
||||||
|
tools/go.sum
|
||||||
|
|
||||||
- name: Get dependencies
|
- name: Get dependencies
|
||||||
if: steps.filter.outputs.go == 'true'
|
if: steps.filter.outputs.go == 'true'
|
||||||
@ -60,6 +63,9 @@ jobs:
|
|||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
|
cache-dependency-path: |
|
||||||
|
go.sum
|
||||||
|
tools/go.sum
|
||||||
|
|
||||||
- name: Get dependencies
|
- name: Get dependencies
|
||||||
if: steps.filter.outputs.go == 'true'
|
if: steps.filter.outputs.go == 'true'
|
||||||
@ -69,3 +75,6 @@ jobs:
|
|||||||
if: steps.filter.outputs.go == 'true'
|
if: steps.filter.outputs.go == 'true'
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
run: go test -v -cover ./...
|
run: go test -v -cover ./...
|
||||||
|
|
||||||
|
- name: Check for uncommitted changes in generated docs
|
||||||
|
run: make docs && git diff --exit-code
|
||||||
|
@ -41,7 +41,7 @@ resource "proxmox_virtual_environment_download_file" "centos_cloud_image" {
|
|||||||
content_type = "iso"
|
content_type = "iso"
|
||||||
datastore_id = "local"
|
datastore_id = "local"
|
||||||
node_name = "pve"
|
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"
|
file_name = "centos8.img"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -76,7 +76,6 @@ resource "proxmox_virtual_environment_download_file" "ubuntu_cloud_image" {
|
|||||||
datastore_id = "local"
|
datastore_id = "local"
|
||||||
node_name = "pve"
|
node_name = "pve"
|
||||||
url = "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img"
|
url = "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img"
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -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`.
|
- `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.
|
- `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` (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).
|
- `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.
|
- `verify` (Boolean) By default `true`. If `false`, no SSL/TLS certificates will be verified.
|
||||||
|
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
## Debian and ubuntu image download
|
## Debian and ubuntu image download
|
||||||
|
|
||||||
resource "proxmox_virtual_environment_download_file" "release_20231211_ubuntu_22_jammy_lxc_img" {
|
resource "proxmox_virtual_environment_download_file" "release_20231211_ubuntu_22_jammy_lxc_img" {
|
||||||
content_type = "vztmpl"
|
content_type = "vztmpl"
|
||||||
datastore_id = "local"
|
datastore_id = "local"
|
||||||
node_name = "pve"
|
node_name = "pve"
|
||||||
url = "https://cloud-images.ubuntu.com/releases/22.04/release-20231211/ubuntu-22.04-server-cloudimg-amd64-root.tar.xz"
|
url = "https://cloud-images.ubuntu.com/releases/22.04/release-20231211/ubuntu-22.04-server-cloudimg-amd64-root.tar.xz"
|
||||||
checksum = "c9997dcfea5d826fd04871f960c513665f2e87dd7450bba99f68a97e60e4586e"
|
checksum = "c9997dcfea5d826fd04871f960c513665f2e87dd7450bba99f68a97e60e4586e"
|
||||||
checksum_algorithm = "sha256"
|
checksum_algorithm = "sha256"
|
||||||
upload_timeout = 4444
|
upload_timeout = 4444
|
||||||
|
overwrite_unmanaged = true
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "proxmox_virtual_environment_download_file" "latest_debian_12_bookworm_qcow2_img" {
|
resource "proxmox_virtual_environment_download_file" "latest_debian_12_bookworm_qcow2_img" {
|
||||||
content_type = "iso"
|
content_type = "iso"
|
||||||
datastore_id = "local"
|
datastore_id = "local"
|
||||||
file_name = "debian-12-generic-amd64.img"
|
file_name = "debian-12-generic-amd64.img"
|
||||||
node_name = "pve"
|
node_name = "pve"
|
||||||
url = "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2"
|
url = "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2"
|
||||||
overwrite = true
|
overwrite = true
|
||||||
|
overwrite_unmanaged = true
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
"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/schema/validator"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"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"
|
||||||
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes"
|
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes"
|
||||||
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/storage"
|
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/storage"
|
||||||
@ -33,9 +34,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ resource.Resource = &downloadFileResource{}
|
_ resource.Resource = &downloadFileResource{}
|
||||||
_ resource.ResourceWithConfigure = &downloadFileResource{}
|
_ resource.ResourceWithConfigure = &downloadFileResource{}
|
||||||
httpRe = regexp.MustCompile(`https?://.*`)
|
httpRegex = regexp.MustCompile(`https?://.*`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func sizeRequiresReplace() planmodifier.Int64 {
|
func sizeRequiresReplace() planmodifier.Int64 {
|
||||||
@ -54,7 +55,7 @@ func (r sizeRequiresReplaceModifier) PlanModifyInt64(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Do not replace on resource destroy.
|
// Do not replace on resource destroy.
|
||||||
if req.Plan.Raw.IsNull() {
|
if req.Plan.Raw.IsNull() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -157,9 +158,10 @@ type downloadFileModel struct {
|
|||||||
ChecksumAlgorithm types.String `tfsdk:"checksum_algorithm"`
|
ChecksumAlgorithm types.String `tfsdk:"checksum_algorithm"`
|
||||||
Verify types.Bool `tfsdk:"verify"`
|
Verify types.Bool `tfsdk:"verify"`
|
||||||
Overwrite types.Bool `tfsdk:"overwrite"`
|
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 {
|
func NewDownloadFileResource() resource.Resource {
|
||||||
return &downloadFileResource{}
|
return &downloadFileResource{}
|
||||||
}
|
}
|
||||||
@ -247,7 +249,7 @@ func (r *downloadFileResource) Schema(
|
|||||||
Description: "The URL to download the file from. Format `https?://.*`.",
|
Description: "The URL to download the file from. Format `https?://.*`.",
|
||||||
Required: true,
|
Required: true,
|
||||||
Validators: []validator.String{
|
Validators: []validator.String{
|
||||||
stringvalidator.RegexMatches(httpRe, "Must match http url regex"),
|
stringvalidator.RegexMatches(httpRegex, "Must match http url regex"),
|
||||||
},
|
},
|
||||||
PlanModifiers: []planmodifier.String{
|
PlanModifiers: []planmodifier.String{
|
||||||
stringplanmodifier.RequiresReplace(),
|
stringplanmodifier.RequiresReplace(),
|
||||||
@ -311,6 +313,14 @@ func (r *downloadFileResource) Schema(
|
|||||||
Computed: true,
|
Computed: true,
|
||||||
Default: booldefault.StaticBool(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(),
|
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 err != nil {
|
||||||
if strings.Contains(err.Error(), "refusing to override existing file") {
|
if isErrFileAlreadyExists(err) {
|
||||||
resp.Diagnostics.AddError(
|
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.",
|
"or is managed by another resource.",
|
||||||
fmt.Sprintf(
|
fmt.Sprintf("File already exists in the datastore: '%s', error: %s",
|
||||||
"File already exists in a datastore: `%s`, "+
|
plan.FileName.ValueString(), err.Error(),
|
||||||
"error: %s",
|
|
||||||
plan.FileName.ValueString(),
|
|
||||||
err.Error(),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
resp.Diagnostics.AddError(
|
resp.Diagnostics.AddError(
|
||||||
"Error creating Download File interface",
|
"Error downloading file from url",
|
||||||
fmt.Sprintf(
|
fmt.Sprintf("Could not download file '%s', unexpected error: %s",
|
||||||
"Could not DownloadFileByURL: `%s`, "+
|
|
||||||
"unexpected error: %s",
|
|
||||||
plan.FileName.ValueString(),
|
plan.FileName.ValueString(),
|
||||||
err.Error(),
|
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")
|
||||||
|
}
|
||||||
|
@ -12,122 +12,164 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
"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 (
|
const (
|
||||||
accTestDownloadIsoFileName = "proxmox_virtual_environment_download_file.iso_image"
|
fakeFileISO = "https://cdn.githubraw.com/rafsaf/a4b19ea5e3485f8da6ca4acf46d09650/raw/d340ec3ddcef9b907ede02f64b5d3f694da5d081/fake_file.iso"
|
||||||
accTestDownloadQcow2FileName = "proxmox_virtual_environment_download_file.qcow2_image"
|
fakeFileQCOW2 = "https://cdn.githubraw.com/rafsaf/036eece601975a3ad632a77fc2809046/raw/10500012fca9b4425b50de67a7258a12cba0c076/fake_file.qcow2"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:paralleltest
|
//nolint:paralleltest
|
||||||
func TestAccResourceDownloadFile(t *testing.T) {
|
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)
|
accProviders := testAccMuxProviders(context.Background(), t)
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
for _, tt := range tests {
|
||||||
ProtoV6ProviderFactories: accProviders,
|
tt := tt
|
||||||
Steps: []resource.TestStep{
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
// Create and Read testing
|
resource.Test(t, resource.TestCase{
|
||||||
{
|
ProtoV6ProviderFactories: accProviders,
|
||||||
Config: testAccResourceDownloadIsoFileCreatedConfig(),
|
Steps: tt.steps,
|
||||||
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"),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
@ -85,12 +85,12 @@ func TestAccResourceFile(t *testing.T) {
|
|||||||
Config: testAccResourceFileMissingSourceConfig(),
|
Config: testAccResourceFileMissingSourceConfig(),
|
||||||
ExpectError: regexp.MustCompile("missing argument"),
|
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"),
|
Config: testAccResourceFileCreatedConfig(snippetFile2.Name(), "overwrite = false"),
|
||||||
ExpectError: regexp.MustCompile("already exists"),
|
ExpectError: regexp.MustCompile("already exists"),
|
||||||
},
|
},
|
||||||
// Allow to overwrite the a file by default
|
// Allow to overwrite the file by default
|
||||||
{
|
{
|
||||||
Config: testAccResourceFileCreatedConfig(snippetFile2.Name()),
|
Config: testAccResourceFileCreatedConfig(snippetFile2.Name()),
|
||||||
Check: testAccResourceFileCreatedCheck("snippets", snippetFile2.Name()),
|
Check: testAccResourceFileCreatedCheck("snippets", snippetFile2.Name()),
|
||||||
|
@ -8,12 +8,9 @@ package tests
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
|
||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAccResourceVM(t *testing.T) {
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -9,6 +9,7 @@ package tests
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -17,7 +18,9 @@ import (
|
|||||||
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
|
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
|
||||||
"github.com/hashicorp/terraform-plugin-mux/tf5to6server"
|
"github.com/hashicorp/terraform-plugin-mux/tf5to6server"
|
||||||
"github.com/hashicorp/terraform-plugin-mux/tf6muxserver"
|
"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/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider"
|
||||||
@ -113,3 +116,36 @@ func getNodeStorageClient() *storage.Client {
|
|||||||
nodesClient := getNodesClient()
|
nodesClient := getNodesClient()
|
||||||
return &storage.Client{Client: nodesClient, StorageName: accTestStorageName}
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
---
|
---
|
||||||
layout: page
|
layout: page
|
||||||
title: Create a VM from a Cloud Image
|
page_title: "Create a VM from a Cloud Image"
|
||||||
parent: Guides
|
subcategory: Guides
|
||||||
subcategory: Virtual Environment
|
|
||||||
description: |-
|
description: |-
|
||||||
This guide explains how to create a VM from a cloud image.
|
This guide explains how to create a VM from a cloud image.
|
||||||
---
|
---
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
---
|
---
|
||||||
layout: page
|
layout: page
|
||||||
title: Configure a VM with Cloud-Init
|
page_title: "Configure a VM with Cloud-Init"
|
||||||
parent: Guides
|
subcategory: Guides
|
||||||
subcategory: Virtual Environment
|
|
||||||
description: |-
|
description: |-
|
||||||
This guide explains how to use the Proxmox provider to create and manage virtual machines using cloud-init.
|
This guide explains how to use the Proxmox provider to create and manage virtual machines using cloud-init.
|
||||||
---
|
---
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
---
|
---
|
||||||
layout: page
|
layout: page
|
||||||
title: Setup a VM with Proxmox
|
page_title: "Setup a VM with Proxmox"
|
||||||
parent: Guides
|
subcategory: Guides
|
||||||
subcategory: Virtual Environment
|
|
||||||
description: |-
|
description: |-
|
||||||
This guide will help you setup a proxmox node in VM using virt-manager for a job.
|
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`.
|
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>.
|
||||||
|
Loading…
Reference in New Issue
Block a user