diff --git a/fwprovider/cluster/acme/datasource_acme_account_test.go b/fwprovider/cluster/acme/datasource_acme_account_test.go new file mode 100644 index 00000000..7db3f8dd --- /dev/null +++ b/fwprovider/cluster/acme/datasource_acme_account_test.go @@ -0,0 +1,63 @@ +//go:build acceptance || all + +/* + * 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 acme_test + +import ( + "fmt" + "testing" + + "github.com/brianvoe/gofakeit/v7" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/bpg/terraform-provider-proxmox/fwprovider/test" +) + +func TestAccDatasourceACMEAccount(t *testing.T) { + t.Parallel() + + te := test.InitEnvironment(t) + accountName := fmt.Sprintf("test-ds-account-%s", gofakeit.Word()) + te.AddTemplateVars(map[string]interface{}{ + "AccountName": accountName, + }) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: te.AccProviders, + Steps: []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_account" "test_account" { + name = "{{.AccountName}}" + contact = "le.ge9ro@passmail.net" + directory = "https://acme-staging-v02.api.letsencrypt.org/directory" + tos = "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" + } + + data "proxmox_virtual_environment_acme_account" "test" { + depends_on = [proxmox_virtual_environment_acme_account.test_account] + name = "{{.AccountName}}" + } + `, test.WithRootUser()), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("data.proxmox_virtual_environment_acme_account.test", map[string]string{ + "name": accountName, + }), + test.ResourceAttributesSet("data.proxmox_virtual_environment_acme_account.test", []string{ + "account.created_at", + "account.status", + "directory", + "location", + "tos", + }), + resource.TestCheckResourceAttrSet("data.proxmox_virtual_environment_acme_account.test", "account.contact.#"), + ), + }, + }, + }) +} diff --git a/fwprovider/cluster/acme/datasource_acme_accounts_test.go b/fwprovider/cluster/acme/datasource_acme_accounts_test.go new file mode 100644 index 00000000..be030854 --- /dev/null +++ b/fwprovider/cluster/acme/datasource_acme_accounts_test.go @@ -0,0 +1,64 @@ +//go:build acceptance || all + +/* + * 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 acme_test + +import ( + "fmt" + "testing" + + "github.com/brianvoe/gofakeit/v7" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/bpg/terraform-provider-proxmox/fwprovider/test" +) + +func TestAccDatasourceACMEAccounts(t *testing.T) { + t.Parallel() + + te := test.InitEnvironment(t) + accountName1 := fmt.Sprintf("test-ds-accounts1-%s", gofakeit.Word()) + accountName2 := fmt.Sprintf("test-ds-accounts2-%s", gofakeit.Word()) + te.AddTemplateVars(map[string]interface{}{ + "AccountName1": accountName1, + "AccountName2": accountName2, + }) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: te.AccProviders, + Steps: []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_account" "test_account1" { + name = "{{.AccountName1}}" + contact = "le.ge9ro@passmail.net" + directory = "https://acme-staging-v02.api.letsencrypt.org/directory" + tos = "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" + } + + resource "proxmox_virtual_environment_acme_account" "test_account2" { + name = "{{.AccountName2}}" + contact = "le.ge9ro@passmail.net" + directory = "https://acme-staging-v02.api.letsencrypt.org/directory" + tos = "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" + } + + data "proxmox_virtual_environment_acme_accounts" "test" { + depends_on = [ + proxmox_virtual_environment_acme_account.test_account1, + proxmox_virtual_environment_acme_account.test_account2 + ] + } + `, test.WithRootUser()), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.proxmox_virtual_environment_acme_accounts.test", "accounts.#"), + ), + }, + }, + }) +} diff --git a/fwprovider/cluster/acme/datasource_acme_plugin_test.go b/fwprovider/cluster/acme/datasource_acme_plugin_test.go new file mode 100644 index 00000000..299b046c --- /dev/null +++ b/fwprovider/cluster/acme/datasource_acme_plugin_test.go @@ -0,0 +1,63 @@ +//go:build acceptance || all + +/* + * 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 acme_test + +import ( + "fmt" + "testing" + + "github.com/brianvoe/gofakeit/v7" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/bpg/terraform-provider-proxmox/fwprovider/test" +) + +func TestAccDatasourceACMEPlugin(t *testing.T) { + t.Parallel() + + te := test.InitEnvironment(t) + pluginName := fmt.Sprintf("test-ds-plugin-%s", gofakeit.Word()) + te.AddTemplateVars(map[string]interface{}{ + "PluginName": pluginName, + }) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: te.AccProviders, + Steps: []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin" { + plugin = "{{.PluginName}}" + api = "cf" + data = { + "CF_API_EMAIL" = "le.ge9ro@passmail.net" + "CF_API_KEY" = "test-api-key" + } + } + + data "proxmox_virtual_environment_acme_plugin" "test" { + depends_on = [proxmox_virtual_environment_acme_dns_plugin.test_plugin] + plugin = "{{.PluginName}}" + } + `), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("data.proxmox_virtual_environment_acme_plugin.test", map[string]string{ + "plugin": pluginName, + }), + test.ResourceAttributesSet("data.proxmox_virtual_environment_acme_plugin.test", []string{ + "api", + "digest", + "validation_delay", + }), + resource.TestCheckResourceAttrSet("data.proxmox_virtual_environment_acme_plugin.test", "data.%"), + ), + }, + }, + }) +} diff --git a/fwprovider/cluster/acme/datasource_acme_plugins_test.go b/fwprovider/cluster/acme/datasource_acme_plugins_test.go new file mode 100644 index 00000000..a05b877f --- /dev/null +++ b/fwprovider/cluster/acme/datasource_acme_plugins_test.go @@ -0,0 +1,96 @@ +//go:build acceptance || all + +/* + * 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 acme_test + +import ( + "fmt" + "testing" + + "github.com/brianvoe/gofakeit/v7" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/bpg/terraform-provider-proxmox/fwprovider/test" +) + +func TestAccDatasourceACMEPlugins(t *testing.T) { + t.Parallel() + + te := test.InitEnvironment(t) + pluginName1 := fmt.Sprintf("test-ds-plugins1-%s", gofakeit.Word()) + pluginName2 := fmt.Sprintf("test-ds-plugins2-%s", gofakeit.Word()) + te.AddTemplateVars(map[string]interface{}{ + "PluginName1": pluginName1, + "PluginName2": pluginName2, + }) + + // First create some plugins to test against + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: te.AccProviders, + Steps: []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin1" { + plugin = "{{.PluginName1}}" + api = "cf" + data = { + "CF_API_EMAIL" = "test1@example.com" + "CF_API_KEY" = "test-api-key-1" + } + } + + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin2" { + plugin = "{{.PluginName2}}" + api = "cf" + data = { + "CF_API_EMAIL" = "test2@example.com" + "CF_API_KEY" = "test-api-key-2" + } + } + `), + }, + }, + }) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: te.AccProviders, + Steps: []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin1" { + plugin = "{{.PluginName1}}" + api = "cf" + data = { + "CF_API_EMAIL" = "le.ge9ro@passmail.net" + "CF_API_KEY" = "test-api-key-1" + } + } + + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin2" { + plugin = "{{.PluginName2}}" + api = "cf" + data = { + "CF_API_EMAIL" = "le.ge9ro@passmail.net" + "CF_API_KEY" = "test-api-key-2" + } + } + + data "proxmox_virtual_environment_acme_plugins" "test" { + depends_on = [ + proxmox_virtual_environment_acme_dns_plugin.test_plugin1, + proxmox_virtual_environment_acme_dns_plugin.test_plugin2 + ] + } + `), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.proxmox_virtual_environment_acme_plugins.test", "plugins.#"), + ), + }, + }, + }) +} diff --git a/fwprovider/cluster/acme/resource_acme_account.go b/fwprovider/cluster/acme/resource_acme_account.go index 15f5dc3a..40b28b22 100644 --- a/fwprovider/cluster/acme/resource_acme_account.go +++ b/fwprovider/cluster/acme/resource_acme_account.go @@ -4,6 +4,24 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +/* + * 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/. + */ + +/* + * 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/. + */ + +/* + * 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 acme import ( @@ -305,9 +323,15 @@ func (r *acmeAccountResource) read(ctx context.Context, data *acmeAccountModel) return false, diags } + // Preserve the original contact value if the API doesn't return it + originalContact := data.Contact.ValueString() + var contact string if len(acc.Account.Contact) > 0 { contact = strings.Replace(acc.Account.Contact[0], "mailto:", "", 1) + } else if originalContact != "" { + // If API doesn't return contact but we had one, preserve it + contact = originalContact } data.Directory = types.StringValue(acc.Directory) diff --git a/fwprovider/cluster/acme/resource_acme_account_test.go b/fwprovider/cluster/acme/resource_acme_account_test.go new file mode 100644 index 00000000..245b9413 --- /dev/null +++ b/fwprovider/cluster/acme/resource_acme_account_test.go @@ -0,0 +1,131 @@ +//go:build acceptance || all + +/* + * 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 acme_test + +import ( + "fmt" + "regexp" + "testing" + + "github.com/brianvoe/gofakeit/v7" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/bpg/terraform-provider-proxmox/fwprovider/test" +) + +func TestAccResourceACMEAccount(t *testing.T) { + t.Parallel() + + te := test.InitEnvironment(t) + accountName := fmt.Sprintf("test-account-%s", gofakeit.Word()) + te.AddTemplateVars(map[string]interface{}{ + "AccountName": accountName, + }) + + tests := []struct { + name string + step []resource.TestStep + }{ + {"basic account creation", []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_account" "test_account" { + name = "{{.AccountName}}" + contact = "le.ge9ro@passmail.net" + directory = "https://acme-staging-v02.api.letsencrypt.org/directory" + tos = "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" + }`, test.WithRootUser()), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("proxmox_virtual_environment_acme_account.test_account", map[string]string{ + "name": accountName, + "directory": "https://acme-staging-v02.api.letsencrypt.org/directory", + "tos": "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf", + }), + test.ResourceAttributesSet("proxmox_virtual_environment_acme_account.test_account", []string{ + "created_at", + "location", + }), + ), + }, + }}, + {"account with EAB", []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_account" "test_account_eab" { + name = "{{.AccountName}}-eab" + contact = "le.ge9ro@passmail.net" + directory = "https://acme-staging-v02.api.letsencrypt.org/directory" + tos = "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" + eab_hmac_key = "test-hmac-key" + eab_kid = "test-kid" + }`, test.WithRootUser()), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("proxmox_virtual_environment_acme_account.test_account_eab", map[string]string{ + "name": fmt.Sprintf("%s-eab", accountName), + "directory": "https://acme-staging-v02.api.letsencrypt.org/directory", + "tos": "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf", + "eab_hmac_key": "test-hmac-key", + "eab_kid": "test-kid", + }), + ), + }, + }}, + {"update account", []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_account" "test_account_update" { + name = "{{.AccountName}}-update" + contact = "le.ge9ro@passmail.net" + directory = "https://acme-staging-v02.api.letsencrypt.org/directory" + tos = "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" + }`, test.WithRootUser()), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("proxmox_virtual_environment_acme_account.test_account_update", map[string]string{ + "name": fmt.Sprintf("%s-update", accountName), + }), + ), + }, + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_account" "test_account_update" { + name = "{{.AccountName}}-update" + contact = "le.ge9ro@passmail.net" + directory = "https://acme-staging-v02.api.letsencrypt.org/directory" + tos = "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" + }`, test.WithRootUser()), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("proxmox_virtual_environment_acme_account.test_account_update", map[string]string{ + "name": fmt.Sprintf("%s-update", accountName), + }), + ), + }, + }}, + {"invalid directory URL", []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_account" "test_account_invalid" { + name = "{{.AccountName}}-invalid" + contact = "le.ge9ro@passmail.net" + directory = "invalid-url" + tos = "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf" + }`, test.WithRootUser()), + ExpectError: regexp.MustCompile(`must be a valid URL`), + }, + }}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: te.AccProviders, + Steps: tt.step, + }) + }) + } +} diff --git a/fwprovider/cluster/acme/resource_acme_dns_plugin_test.go b/fwprovider/cluster/acme/resource_acme_dns_plugin_test.go new file mode 100644 index 00000000..5f8ee8f7 --- /dev/null +++ b/fwprovider/cluster/acme/resource_acme_dns_plugin_test.go @@ -0,0 +1,160 @@ +//go:build acceptance || all + +/* + * 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 acme_test + +import ( + "fmt" + "regexp" + "testing" + + "github.com/brianvoe/gofakeit/v7" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/bpg/terraform-provider-proxmox/fwprovider/test" +) + +func TestAccResourceACMEDNSPlugin(t *testing.T) { + t.Parallel() + + te := test.InitEnvironment(t) + pluginName := fmt.Sprintf("test-plugin-%s", gofakeit.Word()) + te.AddTemplateVars(map[string]interface{}{ + "PluginName": pluginName, + }) + + tests := []struct { + name string + step []resource.TestStep + }{ + {"basic plugin creation", []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin" { + plugin = "{{.PluginName}}" + api = "cf" + data = { + "CF_API_EMAIL" = "test@example.com" + "CF_API_KEY" = "test-api-key" + } + }`), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("proxmox_virtual_environment_acme_dns_plugin.test_plugin", map[string]string{ + "plugin": pluginName, + "api": "cf", + }), + test.ResourceAttributesSet("proxmox_virtual_environment_acme_dns_plugin.test_plugin", []string{ + "digest", + }), + ), + }, + }}, + {"plugin with validation delay", []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin_delay" { + plugin = "{{.PluginName}}-delay" + api = "cf" + data = { + "CF_API_EMAIL" = "test@example.com" + "CF_API_KEY" = "test-api-key" + } + validation_delay = 60 + }`), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("proxmox_virtual_environment_acme_dns_plugin.test_plugin_delay", map[string]string{ + "plugin": fmt.Sprintf("%s-delay", pluginName), + "api": "cf", + "validation_delay": "60", + }), + ), + }, + }}, + {"plugin with disable flag", []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin_disabled" { + plugin = "{{.PluginName}}-disabled" + api = "cf" + data = { + "CF_API_EMAIL" = "test@example.com" + "CF_API_KEY" = "test-api-key" + } + disable = true + }`), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("proxmox_virtual_environment_acme_dns_plugin.test_plugin_disabled", map[string]string{ + "plugin": fmt.Sprintf("%s-disabled", pluginName), + "api": "cf", + "disable": "true", + }), + ), + }, + }}, + {"update plugin", []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin_update" { + plugin = "{{.PluginName}}-update" + api = "cf" + data = { + "CF_API_EMAIL" = "test@example.com" + "CF_API_KEY" = "test-api-key" + } + validation_delay = 30 + }`), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("proxmox_virtual_environment_acme_dns_plugin.test_plugin_update", map[string]string{ + "validation_delay": "30", + }), + ), + }, + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin_update" { + plugin = "{{.PluginName}}-update" + api = "cf" + data = { + "CF_API_EMAIL" = "test@example.com" + "CF_API_KEY" = "test-api-key" + } + validation_delay = 120 + }`), + Check: resource.ComposeTestCheckFunc( + test.ResourceAttributes("proxmox_virtual_environment_acme_dns_plugin.test_plugin_update", map[string]string{ + "validation_delay": "120", + }), + ), + }, + }}, + {"invalid validation delay", []resource.TestStep{ + { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_acme_dns_plugin" "test_plugin_invalid" { + plugin = "{{.PluginName}}-invalid" + api = "cf" + data = { + "CF_API_EMAIL" = "test@example.com" + "CF_API_KEY" = "test-api-key" + } + validation_delay = 200000 + }`), + ExpectError: regexp.MustCompile(`Attribute validation_delay value must be between 0 and 172800`), + }, + }}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: te.AccProviders, + Steps: tt.step, + }) + }) + } +}