From d16c15888b6545e6c4ba20543aeb575ba8563de5 Mon Sep 17 00:00:00 2001 From: Xu Wu Date: Thu, 6 Apr 2023 16:38:13 +0800 Subject: [PATCH 1/4] export arm id --- .../services/keyvault/key_vault_certificate_data_source.go | 6 ++++++ .../services/keyvault/key_vault_certificate_resource.go | 6 ++++++ .../keyvault/key_vault_certificate_resource_test.go | 1 + 3 files changed, 13 insertions(+) diff --git a/internal/services/keyvault/key_vault_certificate_data_source.go b/internal/services/keyvault/key_vault_certificate_data_source.go index 766e365ee887..e553183a5855 100644 --- a/internal/services/keyvault/key_vault_certificate_data_source.go +++ b/internal/services/keyvault/key_vault_certificate_data_source.go @@ -39,6 +39,11 @@ func dataSourceKeyVaultCertificate() *pluginsdk.Resource { ValidateFunc: keyVaultValidate.VaultID, }, + "arm_resource_id": { + Computed: true, + Type: pluginsdk.TypeString, + }, + "version": { Type: pluginsdk.TypeString, Optional: true, @@ -297,6 +302,7 @@ func dataSourceKeyVaultCertificateRead(d *pluginsdk.ResourceData, meta interface d.Set("version", id.Version) d.Set("secret_id", cert.Sid) d.Set("versionless_id", id.VersionlessID()) + d.Set("arm_resource_id", cert.ID) if cert.Sid != nil { secretId, err := parse.ParseNestedItemID(*cert.Sid) diff --git a/internal/services/keyvault/key_vault_certificate_resource.go b/internal/services/keyvault/key_vault_certificate_resource.go index 2c048fda200b..2b3dd7c1f89a 100644 --- a/internal/services/keyvault/key_vault_certificate_resource.go +++ b/internal/services/keyvault/key_vault_certificate_resource.go @@ -376,6 +376,11 @@ func resourceKeyVaultCertificate() *pluginsdk.Resource { }, }, + "arm_resource_id": { + Computed: true, + Type: pluginsdk.TypeString, + }, + "version": { Type: pluginsdk.TypeString, Computed: true, @@ -681,6 +686,7 @@ func resourceKeyVaultCertificateRead(d *pluginsdk.ResourceData, meta interface{} d.Set("version", id.Version) d.Set("secret_id", cert.Sid) d.Set("versionless_id", id.VersionlessID()) + d.Set("arm_resource_id", cert.ID) if cert.Sid != nil { secretId, err := parse.ParseNestedItemID(*cert.Sid) diff --git a/internal/services/keyvault/key_vault_certificate_resource_test.go b/internal/services/keyvault/key_vault_certificate_resource_test.go index 7b016022dac9..dee5581ba6d6 100644 --- a/internal/services/keyvault/key_vault_certificate_resource_test.go +++ b/internal/services/keyvault/key_vault_certificate_resource_test.go @@ -25,6 +25,7 @@ func TestAccKeyVaultCertificate_basicImportPFX(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("certificate_data").Exists(), + check.That(data.ResourceName).Key("arm_resource_id").Exists(), check.That(data.ResourceName).Key("certificate_data_base64").Exists(), check.That(data.ResourceName).Key("certificate_policy.0.secret_properties.0.content_type").HasValue("application/x-pkcs12"), check.That(data.ResourceName).Key("versionless_id").HasValue(fmt.Sprintf("https://acctestkeyvault%s.vault.azure.net/certificates/acctestcert%s", data.RandomString, data.RandomString)), From 4dd6d2aa3ad87d8578914f6045594a65fe6b6d72 Mon Sep 17 00:00:00 2001 From: Xu Wu Date: Thu, 6 Apr 2023 17:05:21 +0800 Subject: [PATCH 2/4] expose keyvault certificate arm style id, just as secret --- .../key_vault_certificate_data_source.go | 11 +- .../key_vault_certificate_resource.go | 11 +- .../key_vault_certificate_resource_test.go | 3 +- .../services/keyvault/parse/certificate.go | 81 ++++++++++ .../keyvault/parse/certificate_test.go | 144 ++++++++++++++++++ .../keyvault/parse/certificate_versionless.go | 75 +++++++++ .../parse/certificate_versionless_test.go | 128 ++++++++++++++++ internal/services/keyvault/resourceids.go | 2 + .../keyvault/validate/certificate_id.go | 23 +++ .../keyvault/validate/certificate_id_test.go | 100 ++++++++++++ .../validate/certificate_versionless_id.go | 23 +++ .../certificate_versionless_id_test.go | 88 +++++++++++ 12 files changed, 684 insertions(+), 5 deletions(-) create mode 100644 internal/services/keyvault/parse/certificate.go create mode 100644 internal/services/keyvault/parse/certificate_test.go create mode 100644 internal/services/keyvault/parse/certificate_versionless.go create mode 100644 internal/services/keyvault/parse/certificate_versionless_test.go create mode 100644 internal/services/keyvault/validate/certificate_id.go create mode 100644 internal/services/keyvault/validate/certificate_id_test.go create mode 100644 internal/services/keyvault/validate/certificate_versionless_id.go create mode 100644 internal/services/keyvault/validate/certificate_versionless_id_test.go diff --git a/internal/services/keyvault/key_vault_certificate_data_source.go b/internal/services/keyvault/key_vault_certificate_data_source.go index e553183a5855..5eb8ddc464d6 100644 --- a/internal/services/keyvault/key_vault_certificate_data_source.go +++ b/internal/services/keyvault/key_vault_certificate_data_source.go @@ -39,7 +39,12 @@ func dataSourceKeyVaultCertificate() *pluginsdk.Resource { ValidateFunc: keyVaultValidate.VaultID, }, - "arm_resource_id": { + "resource_id": { + Computed: true, + Type: pluginsdk.TypeString, + }, + + "resource_versionless_id": { Computed: true, Type: pluginsdk.TypeString, }, @@ -302,7 +307,9 @@ func dataSourceKeyVaultCertificateRead(d *pluginsdk.ResourceData, meta interface d.Set("version", id.Version) d.Set("secret_id", cert.Sid) d.Set("versionless_id", id.VersionlessID()) - d.Set("arm_resource_id", cert.ID) + + d.Set("resource_id", parse.NewCertificateID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name, id.Version).ID()) + d.Set("resource_versionless_id", parse.NewCertificateVersionlessID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name).ID()) if cert.Sid != nil { secretId, err := parse.ParseNestedItemID(*cert.Sid) diff --git a/internal/services/keyvault/key_vault_certificate_resource.go b/internal/services/keyvault/key_vault_certificate_resource.go index 2b3dd7c1f89a..c901efbcbbf9 100644 --- a/internal/services/keyvault/key_vault_certificate_resource.go +++ b/internal/services/keyvault/key_vault_certificate_resource.go @@ -376,7 +376,12 @@ func resourceKeyVaultCertificate() *pluginsdk.Resource { }, }, - "arm_resource_id": { + "resource_id": { + Computed: true, + Type: pluginsdk.TypeString, + }, + + "resource_versionless_id": { Computed: true, Type: pluginsdk.TypeString, }, @@ -686,7 +691,9 @@ func resourceKeyVaultCertificateRead(d *pluginsdk.ResourceData, meta interface{} d.Set("version", id.Version) d.Set("secret_id", cert.Sid) d.Set("versionless_id", id.VersionlessID()) - d.Set("arm_resource_id", cert.ID) + + d.Set("resource_id", parse.NewCertificateID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name, id.Version).ID()) + d.Set("resource_versionless_id", parse.NewCertificateVersionlessID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name).ID()) if cert.Sid != nil { secretId, err := parse.ParseNestedItemID(*cert.Sid) diff --git a/internal/services/keyvault/key_vault_certificate_resource_test.go b/internal/services/keyvault/key_vault_certificate_resource_test.go index dee5581ba6d6..d6db3f7b46d3 100644 --- a/internal/services/keyvault/key_vault_certificate_resource_test.go +++ b/internal/services/keyvault/key_vault_certificate_resource_test.go @@ -25,7 +25,8 @@ func TestAccKeyVaultCertificate_basicImportPFX(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("certificate_data").Exists(), - check.That(data.ResourceName).Key("arm_resource_id").Exists(), + check.That(data.ResourceName).Key("resource_id").Exists(), + check.That(data.ResourceName).Key("resource_versionless_id").Exists(), check.That(data.ResourceName).Key("certificate_data_base64").Exists(), check.That(data.ResourceName).Key("certificate_policy.0.secret_properties.0.content_type").HasValue("application/x-pkcs12"), check.That(data.ResourceName).Key("versionless_id").HasValue(fmt.Sprintf("https://acctestkeyvault%s.vault.azure.net/certificates/acctestcert%s", data.RandomString, data.RandomString)), diff --git a/internal/services/keyvault/parse/certificate.go b/internal/services/keyvault/parse/certificate.go new file mode 100644 index 000000000000..0e776e559d4d --- /dev/null +++ b/internal/services/keyvault/parse/certificate.go @@ -0,0 +1,81 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type CertificateId struct { + SubscriptionId string + ResourceGroup string + VaultName string + Name string + VersionName string +} + +func NewCertificateID(subscriptionId, resourceGroup, vaultName, name, versionName string) CertificateId { + return CertificateId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + VaultName: vaultName, + Name: name, + VersionName: versionName, + } +} + +func (id CertificateId) String() string { + segments := []string{ + fmt.Sprintf("Version Name %q", id.VersionName), + fmt.Sprintf("Name %q", id.Name), + fmt.Sprintf("Vault Name %q", id.VaultName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Certificate", segmentsStr) +} + +func (id CertificateId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.KeyVault/vaults/%s/certificates/%s/versions/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.VaultName, id.Name, id.VersionName) +} + +// CertificateID parses a Certificate ID into an CertificateId struct +func CertificateID(input string) (*CertificateId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := CertificateId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.VaultName, err = id.PopSegment("vaults"); err != nil { + return nil, err + } + if resourceId.Name, err = id.PopSegment("certificates"); err != nil { + return nil, err + } + if resourceId.VersionName, err = id.PopSegment("versions"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/keyvault/parse/certificate_test.go b/internal/services/keyvault/parse/certificate_test.go new file mode 100644 index 000000000000..68a8f8d98e79 --- /dev/null +++ b/internal/services/keyvault/parse/certificate_test.go @@ -0,0 +1,144 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = CertificateId{} + +func TestCertificateIDFormatter(t *testing.T) { + actual := NewCertificateID("12345678-1234-9876-4563-123456789012", "resGroup1", "vault1", "cert1", "version1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/versions/version1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestCertificateID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *CertificateId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing VaultName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/", + Error: true, + }, + + { + // missing value for VaultName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/", + Error: true, + }, + + { + // missing VersionName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/", + Error: true, + }, + + { + // missing value for VersionName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/versions/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/versions/version1", + Expected: &CertificateId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + VaultName: "vault1", + Name: "cert1", + VersionName: "version1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.KEYVAULT/VAULTS/VAULT1/CERTIFICATES/CERT1/VERSIONS/VERSION1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := CertificateID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.VaultName != v.Expected.VaultName { + t.Fatalf("Expected %q but got %q for VaultName", v.Expected.VaultName, actual.VaultName) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + if actual.VersionName != v.Expected.VersionName { + t.Fatalf("Expected %q but got %q for VersionName", v.Expected.VersionName, actual.VersionName) + } + } +} diff --git a/internal/services/keyvault/parse/certificate_versionless.go b/internal/services/keyvault/parse/certificate_versionless.go new file mode 100644 index 000000000000..d39623d6b3a4 --- /dev/null +++ b/internal/services/keyvault/parse/certificate_versionless.go @@ -0,0 +1,75 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type CertificateVersionlessId struct { + SubscriptionId string + ResourceGroup string + VaultName string + CertificateName string +} + +func NewCertificateVersionlessID(subscriptionId, resourceGroup, vaultName, certificateName string) CertificateVersionlessId { + return CertificateVersionlessId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + VaultName: vaultName, + CertificateName: certificateName, + } +} + +func (id CertificateVersionlessId) String() string { + segments := []string{ + fmt.Sprintf("Certificate Name %q", id.CertificateName), + fmt.Sprintf("Vault Name %q", id.VaultName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Certificate Versionless", segmentsStr) +} + +func (id CertificateVersionlessId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.KeyVault/vaults/%s/certificates/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.VaultName, id.CertificateName) +} + +// CertificateVersionlessID parses a CertificateVersionless ID into an CertificateVersionlessId struct +func CertificateVersionlessID(input string) (*CertificateVersionlessId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := CertificateVersionlessId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.VaultName, err = id.PopSegment("vaults"); err != nil { + return nil, err + } + if resourceId.CertificateName, err = id.PopSegment("certificates"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/keyvault/parse/certificate_versionless_test.go b/internal/services/keyvault/parse/certificate_versionless_test.go new file mode 100644 index 000000000000..2501692cdb11 --- /dev/null +++ b/internal/services/keyvault/parse/certificate_versionless_test.go @@ -0,0 +1,128 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = CertificateVersionlessId{} + +func TestCertificateVersionlessIDFormatter(t *testing.T) { + actual := NewCertificateVersionlessID("12345678-1234-9876-4563-123456789012", "resGroup1", "vault1", "cert1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestCertificateVersionlessID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *CertificateVersionlessId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing VaultName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/", + Error: true, + }, + + { + // missing value for VaultName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/", + Error: true, + }, + + { + // missing CertificateName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/", + Error: true, + }, + + { + // missing value for CertificateName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1", + Expected: &CertificateVersionlessId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + VaultName: "vault1", + CertificateName: "cert1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.KEYVAULT/VAULTS/VAULT1/CERTIFICATES/CERT1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := CertificateVersionlessID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.VaultName != v.Expected.VaultName { + t.Fatalf("Expected %q but got %q for VaultName", v.Expected.VaultName, actual.VaultName) + } + if actual.CertificateName != v.Expected.CertificateName { + t.Fatalf("Expected %q but got %q for CertificateName", v.Expected.CertificateName, actual.CertificateName) + } + } +} diff --git a/internal/services/keyvault/resourceids.go b/internal/services/keyvault/resourceids.go index 3ac426d2168c..3f6f1deb8165 100644 --- a/internal/services/keyvault/resourceids.go +++ b/internal/services/keyvault/resourceids.go @@ -10,3 +10,5 @@ package keyvault //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=KeyVersionless -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/keys/key1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Secret -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/secrets/secret1/versions/version1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SecretVersionless -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/secrets/secret1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Certificate -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/versions/version1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=CertificateVersionless -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1 diff --git a/internal/services/keyvault/validate/certificate_id.go b/internal/services/keyvault/validate/certificate_id.go new file mode 100644 index 000000000000..df11f88c2c36 --- /dev/null +++ b/internal/services/keyvault/validate/certificate_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/parse" +) + +func CertificateID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.CertificateID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/keyvault/validate/certificate_id_test.go b/internal/services/keyvault/validate/certificate_id_test.go new file mode 100644 index 000000000000..539f0bb0f3cf --- /dev/null +++ b/internal/services/keyvault/validate/certificate_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestCertificateID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing VaultName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/", + Valid: false, + }, + + { + // missing value for VaultName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/", + Valid: false, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/", + Valid: false, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/", + Valid: false, + }, + + { + // missing VersionName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/", + Valid: false, + }, + + { + // missing value for VersionName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/versions/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1/versions/version1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.KEYVAULT/VAULTS/VAULT1/CERTIFICATES/CERT1/VERSIONS/VERSION1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := CertificateID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/internal/services/keyvault/validate/certificate_versionless_id.go b/internal/services/keyvault/validate/certificate_versionless_id.go new file mode 100644 index 000000000000..ea8029dfc59e --- /dev/null +++ b/internal/services/keyvault/validate/certificate_versionless_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/parse" +) + +func CertificateVersionlessID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.CertificateVersionlessID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/keyvault/validate/certificate_versionless_id_test.go b/internal/services/keyvault/validate/certificate_versionless_id_test.go new file mode 100644 index 000000000000..8287119dd499 --- /dev/null +++ b/internal/services/keyvault/validate/certificate_versionless_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestCertificateVersionlessID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing VaultName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/", + Valid: false, + }, + + { + // missing value for VaultName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/", + Valid: false, + }, + + { + // missing CertificateName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/", + Valid: false, + }, + + { + // missing value for CertificateName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.KeyVault/vaults/vault1/certificates/cert1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.KEYVAULT/VAULTS/VAULT1/CERTIFICATES/CERT1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := CertificateVersionlessID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} From f23424670a9fa7400578984f8e045fbbc11e2bbb Mon Sep 17 00:00:00 2001 From: xuwu1 Date: Fri, 7 Apr 2023 11:19:19 +0800 Subject: [PATCH 3/4] rename resource id field name --- .../keyvault/key_vault_certificate_data_source.go | 8 ++++---- .../keyvault/key_vault_certificate_data_source_test.go | 2 ++ .../services/keyvault/key_vault_certificate_resource.go | 8 ++++---- .../keyvault/key_vault_certificate_resource_test.go | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/internal/services/keyvault/key_vault_certificate_data_source.go b/internal/services/keyvault/key_vault_certificate_data_source.go index 5eb8ddc464d6..30eae53975e9 100644 --- a/internal/services/keyvault/key_vault_certificate_data_source.go +++ b/internal/services/keyvault/key_vault_certificate_data_source.go @@ -39,12 +39,12 @@ func dataSourceKeyVaultCertificate() *pluginsdk.Resource { ValidateFunc: keyVaultValidate.VaultID, }, - "resource_id": { + "resource_manager_id": { Computed: true, Type: pluginsdk.TypeString, }, - "resource_versionless_id": { + "resource_manager_versionless_id": { Computed: true, Type: pluginsdk.TypeString, }, @@ -308,8 +308,8 @@ func dataSourceKeyVaultCertificateRead(d *pluginsdk.ResourceData, meta interface d.Set("secret_id", cert.Sid) d.Set("versionless_id", id.VersionlessID()) - d.Set("resource_id", parse.NewCertificateID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name, id.Version).ID()) - d.Set("resource_versionless_id", parse.NewCertificateVersionlessID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name).ID()) + d.Set("resource_manager_id", parse.NewCertificateID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name, id.Version).ID()) + d.Set("resource_manager_versionless_id", parse.NewCertificateVersionlessID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name).ID()) if cert.Sid != nil { secretId, err := parse.ParseNestedItemID(*cert.Sid) diff --git a/internal/services/keyvault/key_vault_certificate_data_source_test.go b/internal/services/keyvault/key_vault_certificate_data_source_test.go index 9566ef0e2171..fc0f7d3d9b25 100644 --- a/internal/services/keyvault/key_vault_certificate_data_source_test.go +++ b/internal/services/keyvault/key_vault_certificate_data_source_test.go @@ -20,6 +20,8 @@ func TestAccDataSourceKeyVaultCertificate_basic(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).Key("certificate_data").Exists(), check.That(data.ResourceName).Key("certificate_data_base64").Exists(), + check.That(data.ResourceName).Key("resource_manager_id").Exists(), + check.That(data.ResourceName).Key("resource_manager_versionless_id").Exists(), check.That(data.ResourceName).Key("certificate_policy.0.key_properties.0.key_size").HasValue("2048"), check.That(data.ResourceName).Key("certificate_policy.0.key_properties.0.key_type").HasValue("RSA"), check.That(data.ResourceName).Key("not_before").HasValue("2017-10-10T08:27:55Z"), diff --git a/internal/services/keyvault/key_vault_certificate_resource.go b/internal/services/keyvault/key_vault_certificate_resource.go index c901efbcbbf9..aaea1b5e7af9 100644 --- a/internal/services/keyvault/key_vault_certificate_resource.go +++ b/internal/services/keyvault/key_vault_certificate_resource.go @@ -376,12 +376,12 @@ func resourceKeyVaultCertificate() *pluginsdk.Resource { }, }, - "resource_id": { + "resource_manager_id": { Computed: true, Type: pluginsdk.TypeString, }, - "resource_versionless_id": { + "resource_manager_versionless_id": { Computed: true, Type: pluginsdk.TypeString, }, @@ -692,8 +692,8 @@ func resourceKeyVaultCertificateRead(d *pluginsdk.ResourceData, meta interface{} d.Set("secret_id", cert.Sid) d.Set("versionless_id", id.VersionlessID()) - d.Set("resource_id", parse.NewCertificateID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name, id.Version).ID()) - d.Set("resource_versionless_id", parse.NewCertificateVersionlessID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name).ID()) + d.Set("resource_manager_id", parse.NewCertificateID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name, id.Version).ID()) + d.Set("resource_manager_versionless_id", parse.NewCertificateVersionlessID(keyVaultId.SubscriptionId, keyVaultId.ResourceGroup, keyVaultId.Name, id.Name).ID()) if cert.Sid != nil { secretId, err := parse.ParseNestedItemID(*cert.Sid) diff --git a/internal/services/keyvault/key_vault_certificate_resource_test.go b/internal/services/keyvault/key_vault_certificate_resource_test.go index d6db3f7b46d3..792b70fdc8cd 100644 --- a/internal/services/keyvault/key_vault_certificate_resource_test.go +++ b/internal/services/keyvault/key_vault_certificate_resource_test.go @@ -25,8 +25,8 @@ func TestAccKeyVaultCertificate_basicImportPFX(t *testing.T) { Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("certificate_data").Exists(), - check.That(data.ResourceName).Key("resource_id").Exists(), - check.That(data.ResourceName).Key("resource_versionless_id").Exists(), + check.That(data.ResourceName).Key("resource_manager_id").Exists(), + check.That(data.ResourceName).Key("resource_manager_versionless_id").Exists(), check.That(data.ResourceName).Key("certificate_data_base64").Exists(), check.That(data.ResourceName).Key("certificate_policy.0.secret_properties.0.content_type").HasValue("application/x-pkcs12"), check.That(data.ResourceName).Key("versionless_id").HasValue(fmt.Sprintf("https://acctestkeyvault%s.vault.azure.net/certificates/acctestcert%s", data.RandomString, data.RandomString)), From a5a57f1779ef417e52deb2cc1d167280bad953e5 Mon Sep 17 00:00:00 2001 From: xuwu1 Date: Wed, 12 Apr 2023 10:03:44 +0800 Subject: [PATCH 4/4] update kv certificate document --- website/docs/d/key_vault_certificate.html.markdown | 4 ++++ website/docs/r/key_vault_certificate.html.markdown | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/website/docs/d/key_vault_certificate.html.markdown b/website/docs/d/key_vault_certificate.html.markdown index 06a9d7c6b138..d26f60d8b834 100644 --- a/website/docs/d/key_vault_certificate.html.markdown +++ b/website/docs/d/key_vault_certificate.html.markdown @@ -73,6 +73,10 @@ The following attributes are exported: * `tags` - A mapping of tags to assign to the resource. +* `resource_manager_id` - The (Versioned) ID for this Key Vault Certificate. This property points to a specific version of a Key Vault Certificate, as such using this won't auto-rotate values if used in other Azure Services. + +* `resource_manager_versionless_id` - The Versionless ID of the Key Vault Certificate. This property allows other Azure Services (that support it) to auto-rotate their value when the Key Vault Certificate is updated. + --- `certificate_policy` exports the following: diff --git a/website/docs/r/key_vault_certificate.html.markdown b/website/docs/r/key_vault_certificate.html.markdown index 4413589e11e5..982efa923dd8 100644 --- a/website/docs/r/key_vault_certificate.html.markdown +++ b/website/docs/r/key_vault_certificate.html.markdown @@ -334,6 +334,10 @@ In addition to the Arguments listed above - the following Attributes are exporte * `certificate_data_base64` - The Base64 encoded Key Vault Certificate data. * `thumbprint` - The X509 Thumbprint of the Key Vault Certificate represented as a hexadecimal string. * `certificate_attribute` - A `certificate_attribute` block as defined below. + +* `resource_manager_id` - The (Versioned) ID for this Key Vault Certificate. This property points to a specific version of a Key Vault Certificate, as such using this won't auto-rotate values if used in other Azure Services. + +* `resource_manager_versionless_id` - The Versionless ID of the Key Vault Certificate. This property allows other Azure Services (that support it) to auto-rotate their value when the Key Vault Certificate is updated. ---