From dfdf8da3cd53823c03f0ba6c53b58403313537b7 Mon Sep 17 00:00:00 2001 From: Francis Chuang Date: Thu, 9 Mar 2023 14:32:10 +1100 Subject: [PATCH] Add oci_certificates_certificate_bundle and oci_certificates_certificate_authority_bundle data sources --- internal/client/certificates_clients.go | 33 + ...cates_certificate_authority_bundle_test.go | 61 + .../certificates_certificate_bundle_test.go | 64 + internal/provider/register_datasource.go | 5 +- ...ertificate_authority_bundle_data_source.go | 224 +++ ...ificates_certificate_bundle_data_source.go | 272 +++ .../certificates/register_datasource.go | 11 + .../terraform-plugin-sdk/v2/helper/id/id.go | 48 + .../v2/helper/resource/aliases.go | 145 ++ .../helper/resource/environment_variables.go | 35 + .../v2/helper/resource/json.go | 15 + .../v2/helper/resource/plugin.go | 491 ++++++ .../v2/helper/resource/state_shim.go | 301 ++++ .../v2/helper/resource/testcase_providers.go | 61 + .../v2/helper/resource/testcase_validate.go | 87 + .../v2/helper/resource/testing.go | 1524 +++++++++++++++++ .../v2/helper/resource/testing_config.go | 28 + .../v2/helper/resource/testing_new.go | 443 +++++ .../v2/helper/resource/testing_new_config.go | 244 +++ .../resource/testing_new_import_state.go | 281 +++ .../resource/testing_new_refresh_state.go | 96 ++ .../v2/helper/resource/testing_sets.go | 361 ++++ .../v2/helper/resource/teststep_providers.go | 97 ++ .../v2/helper/resource/teststep_validate.go | 128 ++ .../v2/internal/plugintest/config.go | 95 + .../v2/internal/plugintest/doc.go | 10 + .../plugintest/environment_variables.go | 111 ++ .../v2/internal/plugintest/guard.go | 52 + .../v2/internal/plugintest/helper.go | 290 ++++ .../v2/internal/plugintest/util.go | 70 + .../v2/internal/plugintest/working_dir.go | 371 ++++ .../oci-go-sdk/v65/certificates/ca_bundle.go | 45 + .../certificate_authority_bundle.go | 74 + ...ate_authority_bundle_version_collection.go | 39 + ...ficate_authority_bundle_version_summary.go | 72 + .../v65/certificates/certificate_bundle.go | 238 +++ .../certificate_bundle_public_only.go | 145 ++ .../certificate_bundle_version_collection.go | 39 + .../certificate_bundle_version_summary.go | 72 + .../certificate_bundle_with_private_key.go | 151 ++ .../v65/certificates/certificates_client.go | 381 +++++ .../get_ca_bundle_request_response.go | 93 + ...icate_authority_bundle_request_response.go | 159 ++ ...get_certificate_bundle_request_response.go | 207 +++ ...hority_bundle_versions_request_response.go | 183 ++ ...ficate_bundle_versions_request_response.go | 183 ++ .../v65/certificates/revocation_reason.go | 80 + .../v65/certificates/revocation_status.go | 45 + .../oci-go-sdk/v65/certificates/validity.go | 44 + .../v65/certificates/version_stage.go | 72 + vendor/modules.txt | 4 + ...certificate_authority_bundle.html.markdown | 71 + ...tificates_certificate_bundle.html.markdown | 82 + 53 files changed, 8532 insertions(+), 1 deletion(-) create mode 100644 internal/client/certificates_clients.go create mode 100644 internal/integrationtest/certificates_certificate_authority_bundle_test.go create mode 100644 internal/integrationtest/certificates_certificate_bundle_test.go create mode 100644 internal/service/certificates/certificates_certificate_authority_bundle_data_source.go create mode 100644 internal/service/certificates/certificates_certificate_bundle_data_source.go create mode 100644 internal/service/certificates/register_datasource.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/id/id.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/aliases.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/environment_variables.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/json.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/plugin.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/state_shim.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testcase_providers.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testcase_validate.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_config.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_config.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_import_state.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_refresh_state.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_sets.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/teststep_providers.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/teststep_validate.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/config.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/doc.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/environment_variables.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/guard.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/helper.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/util.go create mode 100644 vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/working_dir.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/ca_bundle.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle_version_collection.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle_version_summary.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_public_only.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_version_collection.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_version_summary.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_with_private_key.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificates_client.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_ca_bundle_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_certificate_authority_bundle_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_certificate_bundle_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/list_certificate_authority_bundle_versions_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/list_certificate_bundle_versions_request_response.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/revocation_reason.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/revocation_status.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/validity.go create mode 100644 vendor/github.com/oracle/oci-go-sdk/v65/certificates/version_stage.go create mode 100644 website/docs/d/certificates_certificate_authority_bundle.html.markdown create mode 100644 website/docs/d/certificates_certificate_bundle.html.markdown diff --git a/internal/client/certificates_clients.go b/internal/client/certificates_clients.go new file mode 100644 index 00000000000..3956410e043 --- /dev/null +++ b/internal/client/certificates_clients.go @@ -0,0 +1,33 @@ +// Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +// Licensed under the Mozilla Public License v2.0 + +package client + +import ( + oci_certificates "github.com/oracle/oci-go-sdk/v65/certificates" + oci_common "github.com/oracle/oci-go-sdk/v65/common" +) + +func init() { + RegisterOracleClient("oci_certificates.CertificatesClient", &OracleClient{InitClientFn: initCertificatesCertificatesClient}) +} + +func initCertificatesCertificatesClient(configProvider oci_common.ConfigurationProvider, configureClient ConfigureClient, serviceClientOverrides ServiceClientOverrides) (interface{}, error) { + client, err := oci_certificates.NewCertificatesClientWithConfigurationProvider(configProvider) + if err != nil { + return nil, err + } + err = configureClient(&client.BaseClient) + if err != nil { + return nil, err + } + + if serviceClientOverrides.HostUrlOverride != "" { + client.Host = serviceClientOverrides.HostUrlOverride + } + return &client, nil +} + +func (m *OracleClients) CertificatesClient() *oci_certificates.CertificatesClient { + return m.GetClient("oci_certificates.CertificatesClient").(*oci_certificates.CertificatesClient) +} diff --git a/internal/integrationtest/certificates_certificate_authority_bundle_test.go b/internal/integrationtest/certificates_certificate_authority_bundle_test.go new file mode 100644 index 00000000000..fd5356f6033 --- /dev/null +++ b/internal/integrationtest/certificates_certificate_authority_bundle_test.go @@ -0,0 +1,61 @@ +// Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +// Licensed under the Mozilla Public License v2.0 + +package integrationtest + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/oracle/terraform-provider-oci/httpreplay" + "github.com/oracle/terraform-provider-oci/internal/acctest" + + "github.com/oracle/terraform-provider-oci/internal/utils" +) + +var ( + CertificatesCertificateAuthorityBundleSingularDataSourceRepresentation = map[string]interface{}{ + "certificate_authority_id": acctest.Representation{RepType: acctest.Required, Create: `${oci_certificates_management_certificate_authority.test_certificate_authority.id}`}, + "stage": acctest.Representation{RepType: acctest.Optional, Create: `CURRENT`}, + } + + CertificatesCertificateAuthorityBundleResourceConfig = acctest.GenerateResourceFromRepresentationMap("oci_certificates_management_certificate_authority", "test_certificate_authority", acctest.Required, acctest.Create, certificateAuthorityRepresentation) +) + +// issue-routing-tag: certificates/default +func TestCertificatesCertificateAuthorityBundleResource_basic(t *testing.T) { + httpreplay.SetScenario("TestCertificatesCertificateAuthorityBundleResource_basic") + defer httpreplay.SaveScenario() + + config := acctest.ProviderTestConfig() + + compartmentId := utils.GetEnvSettingWithBlankDefault("compartment_ocid") + compartmentIdVariableStr := fmt.Sprintf("variable \"compartment_id\" { default = \"%s\" }\n", compartmentId) + + singularDatasourceName := "data.oci_certificates_certificate_authority_bundle.test_certificate_authority_bundle" + + acctest.SaveConfigContent("", "", "", t) + acctest.ResourceTest(t, nil, []resource.TestStep{ + // verify singular datasource + { + Config: config + + acctest.GenerateDataSourceFromRepresentationMap("oci_certificates_certificate_authority_bundle", "test_certificate_authority_bundle", acctest.Optional, acctest.Create, CertificatesCertificateAuthorityBundleSingularDataSourceRepresentation) + + compartmentIdVariableStr + CertificatesCertificateAuthorityBundleResourceConfig, + Check: acctest.ComposeAggregateTestCheckFuncWrapper( + resource.TestCheckResourceAttrSet(singularDatasourceName, "cert_chain_pem"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "certificate_authority_id"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "certificate_authority_name"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "certificate_pem"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "serial_number"), + resource.TestCheckResourceAttr(singularDatasourceName, "stages.#", "2"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "time_created"), + resource.TestCheckResourceAttr(singularDatasourceName, "validity.#", "1"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "validity.0.time_of_validity_not_before"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "validity.0.time_of_validity_not_after"), + resource.TestCheckResourceAttr(singularDatasourceName, "version_number", "1"), + ), + }, + }) +} diff --git a/internal/integrationtest/certificates_certificate_bundle_test.go b/internal/integrationtest/certificates_certificate_bundle_test.go new file mode 100644 index 00000000000..d8aae41c73a --- /dev/null +++ b/internal/integrationtest/certificates_certificate_bundle_test.go @@ -0,0 +1,64 @@ +// Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +// Licensed under the Mozilla Public License v2.0 + +package integrationtest + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/oracle/terraform-provider-oci/httpreplay" + "github.com/oracle/terraform-provider-oci/internal/acctest" + + "github.com/oracle/terraform-provider-oci/internal/utils" +) + +var ( + CertificatesCertificateBundleSingularDataSourceRepresentation = map[string]interface{}{ + "certificate_id": acctest.Representation{RepType: acctest.Required, Create: `${oci_certificates_management_certificate.test_certificate.id}`}, + "certificate_bundle_type": acctest.Representation{RepType: acctest.Optional, Create: `CERTIFICATE_CONTENT_WITH_PRIVATE_KEY`}, + "stage": acctest.Representation{RepType: acctest.Optional, Create: `CURRENT`}, + } + + CertificatesCertificateBundleResourceConfig = acctest.GenerateResourceFromRepresentationMap("oci_certificates_management_certificate", "test_certificate", acctest.Required, acctest.Create, certificatesManagementCertificateRepresentation) +) + +// issue-routing-tag: certificates/default +func TestCertificatesCertificateBundleResource_basic(t *testing.T) { + httpreplay.SetScenario("TestCertificatesCertificateBundleResource_basic") + defer httpreplay.SaveScenario() + + config := acctest.ProviderTestConfig() + + compartmentId := utils.GetEnvSettingWithBlankDefault("compartment_ocid") + compartmentIdVariableStr := fmt.Sprintf("variable \"compartment_id\" { default = \"%s\" }\n", compartmentId) + + singularDatasourceName := "data.oci_certificates_certificate_bundle.test_certificate_bundle" + + acctest.SaveConfigContent("", "", "", t) + acctest.ResourceTest(t, nil, []resource.TestStep{ + // verify singular datasource + { + Config: config + + acctest.GenerateDataSourceFromRepresentationMap("oci_certificates_certificate_bundle", "test_certificate_bundle", acctest.Optional, acctest.Create, CertificatesCertificateBundleSingularDataSourceRepresentation) + + compartmentIdVariableStr + CertificatesCertificateBundleResourceConfig, + Check: acctest.ComposeAggregateTestCheckFuncWrapper( + resource.TestCheckResourceAttrSet(singularDatasourceName, "cert_chain_pem"), + resource.TestCheckResourceAttr(singularDatasourceName, "certificate_bundle_type", "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "certificate_id"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "certificate_name"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "certificate_pem"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "private_key_pem"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "serial_number"), + resource.TestCheckResourceAttr(singularDatasourceName, "stages.#", "2"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "time_created"), + resource.TestCheckResourceAttr(singularDatasourceName, "validity.#", "1"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "validity.0.time_of_validity_not_before"), + resource.TestCheckResourceAttrSet(singularDatasourceName, "validity.0.time_of_validity_not_after"), + resource.TestCheckResourceAttr(singularDatasourceName, "version_number", "1"), + ), + }, + }) +} diff --git a/internal/provider/register_datasource.go b/internal/provider/register_datasource.go index cd6aa9e6e1c..5f0c18baaf0 100644 --- a/internal/provider/register_datasource.go +++ b/internal/provider/register_datasource.go @@ -27,6 +27,7 @@ import ( tf_blockchain "github.com/oracle/terraform-provider-oci/internal/service/blockchain" tf_budget "github.com/oracle/terraform-provider-oci/internal/service/budget" tf_capacity_management "github.com/oracle/terraform-provider-oci/internal/service/capacity_management" + tf_certificates "github.com/oracle/terraform-provider-oci/internal/service/certificates" tf_certificates_management "github.com/oracle/terraform-provider-oci/internal/service/certificates_management" tf_cloud_bridge "github.com/oracle/terraform-provider-oci/internal/service/cloud_bridge" tf_cloud_guard "github.com/oracle/terraform-provider-oci/internal/service/cloud_guard" @@ -202,6 +203,9 @@ func init() { if common.CheckForEnabledServices("capacitymanagement") { tf_capacity_management.RegisterDatasource() } + if common.CheckForEnabledServices("certificates") { + tf_certificates.RegisterDatasource() + } if common.CheckForEnabledServices("certificatesmanagement") { tf_certificates_management.RegisterDatasource() } @@ -523,5 +527,4 @@ func init() { if common.CheckForEnabledServices("zpr") { tf_zpr.RegisterDatasource() } - } diff --git a/internal/service/certificates/certificates_certificate_authority_bundle_data_source.go b/internal/service/certificates/certificates_certificate_authority_bundle_data_source.go new file mode 100644 index 00000000000..40e665b2268 --- /dev/null +++ b/internal/service/certificates/certificates_certificate_authority_bundle_data_source.go @@ -0,0 +1,224 @@ +// Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +// Licensed under the Mozilla Public License v2.0 + +package certificates + +import ( + "context" + "fmt" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + oci_certificates "github.com/oracle/oci-go-sdk/v65/certificates" + "github.com/oracle/terraform-provider-oci/internal/client" + "github.com/oracle/terraform-provider-oci/internal/tfresource" +) + +func CertificatesCertificateAuthorityBundleDataSource() *schema.Resource { + return &schema.Resource{ + Read: readCertificatesCertificateAuthorityBundle, + Schema: map[string]*schema.Schema{ + "cert_chain_pem": { + Type: schema.TypeString, + Computed: true, + }, + "certificate_authority_id": { + Type: schema.TypeString, + Required: true, + }, + "certificate_authority_name": { + Type: schema.TypeString, + Computed: true, + }, + "certificate_pem": { + Type: schema.TypeString, + Computed: true, + }, + "certificate_authority_version_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "revocation_status": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "time_revoked": { + Type: schema.TypeString, + Required: true, + }, + "revocation_reason": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "serial_number": { + Type: schema.TypeString, + Computed: true, + }, + "stage": { + Type: schema.TypeString, + DiffSuppressFunc: tfresource.EqualIgnoreCaseSuppressDiff, + ValidateFunc: validation.StringInSlice([]string{ + "CURRENT", + "PENDING", + "LATEST", + "PREVIOUS", + "DEPRECATED", + }, true), + Optional: true, + }, + "stages": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "time_created": { + Type: schema.TypeString, + Computed: true, + }, + "validity": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "time_of_validity_not_before": { + Type: schema.TypeString, + Required: true, + }, + "time_of_validity_not_after": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "version_name": { + Type: schema.TypeString, + Computed: true, + }, + "version_number": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + }, + } +} + +func readCertificatesCertificateAuthorityBundle(d *schema.ResourceData, m interface{}) error { + sync := &CertificatesCertificateAuthorityBundleDataSourceCrud{} + sync.D = d + sync.Client = m.(*client.OracleClients).CertificatesClient() + + return tfresource.ReadResource(sync) +} + +type CertificatesCertificateAuthorityBundleDataSourceCrud struct { + D *schema.ResourceData + Client *oci_certificates.CertificatesClient + Res *oci_certificates.GetCertificateAuthorityBundleResponse +} + +func (s *CertificatesCertificateAuthorityBundleDataSourceCrud) VoidState() { + s.D.SetId("") +} + +func (s *CertificatesCertificateAuthorityBundleDataSourceCrud) Get() error { + request := oci_certificates.GetCertificateAuthorityBundleRequest{} + + if certificateAuthorityId, ok := s.D.GetOkExists("certificate_authority_id"); ok { + tmp := certificateAuthorityId.(string) + request.CertificateAuthorityId = &tmp + } + + if versionNumber, ok := s.D.GetOkExists("version_number"); ok { + tmp := versionNumber.(string) + tmpInt64, err := strconv.ParseInt(tmp, 10, 64) + if err != nil { + return fmt.Errorf("unable to convert versionNumber string: %s to an int64 and encountered error: %v", tmp, err) + } + request.VersionNumber = &tmpInt64 + } + + if certificateAuthorityVersionName, ok := s.D.GetOkExists("certificate_authority_version_name"); ok { + tmp := certificateAuthorityVersionName.(string) + request.CertificateAuthorityVersionName = &tmp + } + + if stage, ok := s.D.GetOkExists("stage"); ok { + request.Stage = oci_certificates.GetCertificateAuthorityBundleStageEnum(stage.(string)) + } + + request.RequestMetadata.RetryPolicy = tfresource.GetRetryPolicy(false, "certificates") + + response, err := s.Client.GetCertificateAuthorityBundle(context.Background(), request) + if err != nil { + return err + } + + s.Res = &response + return nil +} + +func (s *CertificatesCertificateAuthorityBundleDataSourceCrud) SetData() error { + if s.Res == nil { + return nil + } + + s.D.SetId(*s.Res.CertificateAuthorityId) + + if s.Res.CertChainPem != nil { + s.D.Set("cert_chain_pem", *s.Res.CertChainPem) + } + + if s.Res.CertificateAuthorityName != nil { + s.D.Set("certificate_authority_name", *s.Res.CertificateAuthorityName) + } + + if s.Res.CertificatePem != nil { + s.D.Set("certificate_pem", *s.Res.CertificatePem) + } + + if s.Res.RevocationStatus != nil { + s.D.Set("revocation_status", []interface{}{revocationStatusToMap(s.Res.RevocationStatus)}) + } else { + s.D.Set("revocation_status", nil) + } + + if s.Res.SerialNumber != nil { + s.D.Set("serial_number", *s.Res.SerialNumber) + } + + stages := []interface{}{} + for _, item := range s.Res.Stages { + stages = append(stages, item) + } + s.D.Set("stages", stages) + + if s.Res.TimeCreated != nil { + s.D.Set("time_created", s.Res.TimeCreated.String()) + } + + if s.Res.Validity != nil { + s.D.Set("validity", []interface{}{validityToMap(s.Res.Validity)}) + } else { + s.D.Set("validity", nil) + } + + if s.Res.VersionName != nil { + s.D.Set("version_name", *s.Res.VersionName) + } + + if s.Res.VersionNumber != nil { + s.D.Set("version_number", strconv.FormatInt(*s.Res.VersionNumber, 10)) + } + + return nil +} diff --git a/internal/service/certificates/certificates_certificate_bundle_data_source.go b/internal/service/certificates/certificates_certificate_bundle_data_source.go new file mode 100644 index 00000000000..bca920315fe --- /dev/null +++ b/internal/service/certificates/certificates_certificate_bundle_data_source.go @@ -0,0 +1,272 @@ +// Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +// Licensed under the Mozilla Public License v2.0 + +package certificates + +import ( + "context" + "fmt" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + oci_certificates "github.com/oracle/oci-go-sdk/v65/certificates" + "github.com/oracle/terraform-provider-oci/internal/client" + "github.com/oracle/terraform-provider-oci/internal/tfresource" +) + +func CertificatesCertificateBundleDataSource() *schema.Resource { + return &schema.Resource{ + Read: readCertificatesCertificateBundle, + Schema: map[string]*schema.Schema{ + "cert_chain_pem": { + Type: schema.TypeString, + Computed: true, + }, + "certificate_bundle_type": { + Type: schema.TypeString, + DiffSuppressFunc: tfresource.EqualIgnoreCaseSuppressDiff, + ValidateFunc: validation.StringInSlice([]string{ + "CERTIFICATE_CONTENT_PUBLIC_ONLY", + "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY", + }, true), + Optional: true, + Computed: true, + }, + "certificate_id": { + Type: schema.TypeString, + Required: true, + }, + "certificate_name": { + Type: schema.TypeString, + Computed: true, + }, + "certificate_pem": { + Type: schema.TypeString, + Computed: true, + }, + "certificate_version_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "private_key_pem": { + Type: schema.TypeString, + Computed: true, + }, + "private_key_pem_passphrase": { + Type: schema.TypeString, + Computed: true, + }, + "revocation_status": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "time_revoked": { + Type: schema.TypeString, + Required: true, + }, + "revocation_reason": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "serial_number": { + Type: schema.TypeString, + Computed: true, + }, + "stage": { + Type: schema.TypeString, + DiffSuppressFunc: tfresource.EqualIgnoreCaseSuppressDiff, + ValidateFunc: validation.StringInSlice([]string{ + "CURRENT", + "PENDING", + "LATEST", + "PREVIOUS", + "DEPRECATED", + }, true), + Optional: true, + }, + "stages": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "time_created": { + Type: schema.TypeString, + Computed: true, + }, + "validity": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "time_of_validity_not_before": { + Type: schema.TypeString, + Required: true, + }, + "time_of_validity_not_after": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "version_number": { + Type: schema.TypeString, + Computed: true, + Optional: true, + }, + }, + } +} + +func readCertificatesCertificateBundle(d *schema.ResourceData, m interface{}) error { + sync := &CertificatesCertificateBundleDataSourceCrud{} + sync.D = d + sync.Client = m.(*client.OracleClients).CertificatesClient() + + return tfresource.ReadResource(sync) +} + +type CertificatesCertificateBundleDataSourceCrud struct { + D *schema.ResourceData + Client *oci_certificates.CertificatesClient + Res *oci_certificates.GetCertificateBundleResponse +} + +func (s *CertificatesCertificateBundleDataSourceCrud) VoidState() { + s.D.SetId("") +} + +func (s *CertificatesCertificateBundleDataSourceCrud) Get() error { + request := oci_certificates.GetCertificateBundleRequest{} + + if certificateId, ok := s.D.GetOkExists("certificate_id"); ok { + tmp := certificateId.(string) + request.CertificateId = &tmp + } + + if versionNumber, ok := s.D.GetOkExists("version_number"); ok { + tmp := versionNumber.(string) + tmpInt64, err := strconv.ParseInt(tmp, 10, 64) + if err != nil { + return fmt.Errorf("unable to convert versionNumber string: %s to an int64 and encountered error: %v", tmp, err) + } + request.VersionNumber = &tmpInt64 + } + + if certificateVersionName, ok := s.D.GetOkExists("certificate_version_name"); ok { + tmp := certificateVersionName.(string) + request.CertificateVersionName = &tmp + } + + if stage, ok := s.D.GetOkExists("stage"); ok { + request.Stage = oci_certificates.GetCertificateBundleStageEnum(stage.(string)) + } + + if certificateBundleType, ok := s.D.GetOkExists("certificate_bundle_type"); ok { + request.CertificateBundleType = oci_certificates.GetCertificateBundleCertificateBundleTypeEnum(certificateBundleType.(string)) + } + + request.RequestMetadata.RetryPolicy = tfresource.GetRetryPolicy(false, "certificates") + + response, err := s.Client.GetCertificateBundle(context.Background(), request) + if err != nil { + return err + } + + s.Res = &response + return nil +} + +func (s *CertificatesCertificateBundleDataSourceCrud) SetData() error { + if s.Res == nil { + return nil + } + + s.D.SetId(*s.Res.GetCertificateId()) + + if s.Res.GetCertificateName() != nil { + s.D.Set("certificate_name", *s.Res.GetCertificateName()) + } + + if s.Res.GetVersionNumber() != nil { + s.D.Set("version_number", strconv.FormatInt(*s.Res.GetVersionNumber(), 10)) + } + + if s.Res.GetSerialNumber() != nil { + s.D.Set("serial_number", *s.Res.GetSerialNumber()) + } + + if s.Res.GetTimeCreated() != nil { + s.D.Set("time_created", s.Res.GetTimeCreated().String()) + } + + if s.Res.GetValidity() != nil { + s.D.Set("validity", []interface{}{validityToMap(s.Res.GetValidity())}) + } else { + s.D.Set("validity", nil) + } + + stages := []interface{}{} + for _, item := range s.Res.GetStages() { + stages = append(stages, item) + } + s.D.Set("stages", stages) + + if s.Res.GetCertificatePem() != nil { + s.D.Set("certificate_pem", *s.Res.GetCertificatePem()) + } + + if s.Res.GetCertChainPem() != nil { + s.D.Set("cert_chain_pem", *s.Res.GetCertChainPem()) + } + + if s.Res.GetVersionName() != nil { + s.D.Set("version_name", *s.Res.GetVersionName()) + } + + if s.Res.GetRevocationStatus() != nil { + s.D.Set("revocation_status", []interface{}{revocationStatusToMap(s.Res.GetRevocationStatus())}) + } else { + s.D.Set("revocation_status", nil) + } + + if bundle, ok := s.Res.CertificateBundle.(oci_certificates.CertificateBundleWithPrivateKey); ok { + if bundle.PrivateKeyPem != nil { + s.D.Set("private_key_pem", *bundle.PrivateKeyPem) + } + if bundle.PrivateKeyPemPassphrase != nil { + s.D.Set("private_key_passphrase", *bundle.PrivateKeyPemPassphrase) + } + s.D.Set("certificate_bundle_type", "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY") + } else { + s.D.Set("certificate_bundle_type", "CERTIFICATE_CONTENT_PUBLIC_ONLY") + } + + return nil +} + +func validityToMap(obj *oci_certificates.Validity) map[string]interface{} { + result := map[string]interface{}{ + "time_of_validity_not_before": obj.TimeOfValidityNotBefore.String(), + "time_of_validity_not_after": obj.TimeOfValidityNotAfter.String(), + } + + return result +} + +func revocationStatusToMap(obj *oci_certificates.RevocationStatus) map[string]interface{} { + result := map[string]interface{}{ + "time_revoked": obj.TimeRevoked.String(), + "revocation_reason": obj.RevocationReason, + } + + return result +} diff --git a/internal/service/certificates/register_datasource.go b/internal/service/certificates/register_datasource.go new file mode 100644 index 00000000000..cde593914c8 --- /dev/null +++ b/internal/service/certificates/register_datasource.go @@ -0,0 +1,11 @@ +// Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. +// Licensed under the Mozilla Public License v2.0 + +package certificates + +import "github.com/oracle/terraform-provider-oci/internal/tfresource" + +func RegisterDatasource() { + tfresource.RegisterDatasource("oci_certificates_certificate_bundle", CertificatesCertificateBundleDataSource()) + tfresource.RegisterDatasource("oci_certificates_certificate_authority_bundle", CertificatesCertificateAuthorityBundleDataSource()) +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/id/id.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/id/id.go new file mode 100644 index 00000000000..0491252c855 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/id/id.go @@ -0,0 +1,48 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package id + +import ( + "fmt" + "strings" + "sync" + "time" +) + +const UniqueIdPrefix = `terraform-` + +// idCounter is a monotonic counter for generating ordered unique ids. +var idMutex sync.Mutex +var idCounter uint32 + +// Helper for a resource to generate a unique identifier w/ default prefix +func UniqueId() string { + return PrefixedUniqueId(UniqueIdPrefix) +} + +// UniqueIDSuffixLength is the string length of the suffix generated by +// PrefixedUniqueId. This can be used by length validation functions to +// ensure prefixes are the correct length for the target field. +const UniqueIDSuffixLength = 26 + +// Helper for a resource to generate a unique identifier w/ given prefix +// +// After the prefix, the ID consists of an incrementing 26 digit value (to match +// previous timestamp output). After the prefix, the ID consists of a timestamp +// and an incrementing 8 hex digit value The timestamp means that multiple IDs +// created with the same prefix will sort in the order of their creation, even +// across multiple terraform executions, as long as the clock is not turned back +// between calls, and as long as any given terraform execution generates fewer +// than 4 billion IDs. +func PrefixedUniqueId(prefix string) string { + // Be precise to 4 digits of fractional seconds, but remove the dot before the + // fractional seconds. + timestamp := strings.Replace( + time.Now().UTC().Format("20060102150405.0000"), ".", "", 1) + + idMutex.Lock() + defer idMutex.Unlock() + idCounter++ + return fmt.Sprintf("%s%s%08x", prefix, timestamp, idCounter) +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/aliases.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/aliases.go new file mode 100644 index 00000000000..275137d8129 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/aliases.go @@ -0,0 +1,145 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" +) + +// Deprecated: Use helper/id package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +const UniqueIdPrefix = id.UniqueIdPrefix + +// Helper for a resource to generate a unique identifier w/ default prefix +// +// Deprecated: Use helper/id package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +func UniqueId() string { + return id.UniqueId() +} + +// Deprecated: Use helper/id package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +const UniqueIDSuffixLength = id.UniqueIDSuffixLength + +// Helper for a resource to generate a unique identifier w/ given prefix +// +// After the prefix, the ID consists of an incrementing 26 digit value (to match +// previous timestamp output). After the prefix, the ID consists of a timestamp +// and an incrementing 8 hex digit value The timestamp means that multiple IDs +// created with the same prefix will sort in the order of their creation, even +// across multiple terraform executions, as long as the clock is not turned back +// between calls, and as long as any given terraform execution generates fewer +// than 4 billion IDs. +// +// Deprecated: Use helper/id package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +func PrefixedUniqueId(prefix string) string { + return id.PrefixedUniqueId(prefix) +} + +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +type NotFoundError = retry.NotFoundError + +// UnexpectedStateError is returned when Refresh returns a state that's neither in Target nor Pending +// +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +type UnexpectedStateError = retry.UnexpectedStateError + +// TimeoutError is returned when WaitForState times out +// +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +type TimeoutError = retry.TimeoutError + +// StateRefreshFunc is a function type used for StateChangeConf that is +// responsible for refreshing the item being watched for a state change. +// +// It returns three results. `result` is any object that will be returned +// as the final object after waiting for state change. This allows you to +// return the final updated object, for example an EC2 instance after refreshing +// it. A nil result represents not found. +// +// `state` is the latest state of that object. And `err` is any error that +// may have happened while refreshing the state. +// +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +type StateRefreshFunc = retry.StateRefreshFunc + +// StateChangeConf is the configuration struct used for `WaitForState`. +// +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +type StateChangeConf = retry.StateChangeConf + +// RetryFunc is the function retried until it succeeds. +// +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +type RetryFunc = retry.RetryFunc + +// RetryContext is a basic wrapper around StateChangeConf that will just retry +// a function until it no longer returns an error. +// +// Cancellation from the passed in context will propagate through to the +// underlying StateChangeConf +// +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +func RetryContext(ctx context.Context, timeout time.Duration, f RetryFunc) error { + return retry.RetryContext(ctx, timeout, f) +} + +// Retry is a basic wrapper around StateChangeConf that will just retry +// a function until it no longer returns an error. +// +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +func Retry(timeout time.Duration, f RetryFunc) error { + return retry.Retry(timeout, f) +} + +// RetryError is the required return type of RetryFunc. It forces client code +// to choose whether or not a given error is retryable. +// +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +type RetryError = retry.RetryError + +// RetryableError is a helper to create a RetryError that's retryable from a +// given error. To prevent logic errors, will return an error when passed a +// nil error. +// +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +func RetryableError(err error) *RetryError { + r := retry.RetryableError(err) + + return &RetryError{ + Err: r.Err, + Retryable: r.Retryable, + } +} + +// NonRetryableError is a helper to create a RetryError that's _not_ retryable +// from a given error. To prevent logic errors, will return an error when +// passed a nil error. +// +// Deprecated: Use helper/retry package instead. This is required for migrating acceptance +// testing to terraform-plugin-testing. +func NonRetryableError(err error) *RetryError { + r := retry.NonRetryableError(err) + + return &RetryError{ + Err: r.Err, + Retryable: r.Retryable, + } +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/environment_variables.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/environment_variables.go new file mode 100644 index 00000000000..981908799e6 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/environment_variables.go @@ -0,0 +1,35 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +// Environment variables for acceptance testing. Additional environment +// variable constants can be found in the internal/plugintest package. +const ( + // Environment variable to enable acceptance tests using this package's + // ParallelTest and Test functions whose TestCase does not enable the + // IsUnitTest field. Defaults to disabled, in which each test will call + // (*testing.T).Skip(). Can be set to any value to enable acceptance tests, + // however "1" is conventional. + EnvTfAcc = "TF_ACC" + + // Environment variable with hostname for the provider under acceptance + // test. The hostname is the first portion of the full provider source + // address, such as "example.com" in example.com/myorg/myprovider. Defaults + // to "registry.terraform.io". + // + // Only required if any Terraform configuration set via the TestStep + // type Config field includes a provider source, such as the terraform + // configuration block required_providers attribute. + EnvTfAccProviderHost = "TF_ACC_PROVIDER_HOST" + + // Environment variable with namespace for the provider under acceptance + // test. The namespace is the second portion of the full provider source + // address, such as "myorg" in registry.terraform.io/myorg/myprovider. + // Defaults to "-" for Terraform 0.12-0.13 compatibility and "hashicorp". + // + // Only required if any Terraform configuration set via the TestStep + // type Config field includes a provider source, such as the terraform + // configuration block required_providers attribute. + EnvTfAccProviderNamespace = "TF_ACC_PROVIDER_NAMESPACE" +) diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/json.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/json.go new file mode 100644 index 00000000000..9cd6a1b9832 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/json.go @@ -0,0 +1,15 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "bytes" + "encoding/json" +) + +func unmarshalJSON(data []byte, v interface{}) error { + dec := json.NewDecoder(bytes.NewReader(data)) + dec.UseNumber() + return dec.Decode(v) +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/plugin.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/plugin.go new file mode 100644 index 00000000000..14d869466b5 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/plugin.go @@ -0,0 +1,491 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "fmt" + "io" + "os" + "strings" + "sync" + + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/terraform-exec/tfexec" + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest" + "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" + testing "github.com/mitchellh/go-testing-interface" +) + +// protov5ProviderFactory is a function which is called to start a protocol +// version 5 provider server. +type protov5ProviderFactory func() (tfprotov5.ProviderServer, error) + +// protov5ProviderFactories is a mapping of provider addresses to provider +// factory for protocol version 5 provider servers. +type protov5ProviderFactories map[string]func() (tfprotov5.ProviderServer, error) + +// merge combines provider factories. +// +// In case of an overlapping entry, the later entry will overwrite the previous +// value. +func (pf protov5ProviderFactories) merge(otherPfs ...protov5ProviderFactories) protov5ProviderFactories { + result := make(protov5ProviderFactories) + + for name, providerFactory := range pf { + result[name] = providerFactory + } + + for _, otherPf := range otherPfs { + for name, providerFactory := range otherPf { + result[name] = providerFactory + } + } + + return result +} + +// protov6ProviderFactory is a function which is called to start a protocol +// version 6 provider server. +type protov6ProviderFactory func() (tfprotov6.ProviderServer, error) + +// protov6ProviderFactories is a mapping of provider addresses to provider +// factory for protocol version 6 provider servers. +type protov6ProviderFactories map[string]func() (tfprotov6.ProviderServer, error) + +// merge combines provider factories. +// +// In case of an overlapping entry, the later entry will overwrite the previous +// value. +func (pf protov6ProviderFactories) merge(otherPfs ...protov6ProviderFactories) protov6ProviderFactories { + result := make(protov6ProviderFactories) + + for name, providerFactory := range pf { + result[name] = providerFactory + } + + for _, otherPf := range otherPfs { + for name, providerFactory := range otherPf { + result[name] = providerFactory + } + } + + return result +} + +// sdkProviderFactory is a function which is called to start a SDK provider +// server. +type sdkProviderFactory func() (*schema.Provider, error) + +// protov6ProviderFactories is a mapping of provider addresses to provider +// factory for protocol version 6 provider servers. +type sdkProviderFactories map[string]func() (*schema.Provider, error) + +// merge combines provider factories. +// +// In case of an overlapping entry, the later entry will overwrite the previous +// value. +func (pf sdkProviderFactories) merge(otherPfs ...sdkProviderFactories) sdkProviderFactories { + result := make(sdkProviderFactories) + + for name, providerFactory := range pf { + result[name] = providerFactory + } + + for _, otherPf := range otherPfs { + for name, providerFactory := range otherPf { + result[name] = providerFactory + } + } + + return result +} + +type providerFactories struct { + legacy sdkProviderFactories + protov5 protov5ProviderFactories + protov6 protov6ProviderFactories +} + +func runProviderCommand(ctx context.Context, t testing.T, f func() error, wd *plugintest.WorkingDir, factories *providerFactories) error { + // don't point to this as a test failure location + // point to whatever called it + t.Helper() + + // This should not happen, but prevent panics just in case. + if factories == nil { + err := fmt.Errorf("Provider factories are missing to run Terraform command. Please report this bug in the testing framework.") + logging.HelperResourceError(ctx, err.Error()) + return err + } + + // Run the providers in the same process as the test runner using the + // reattach behavior in Terraform. This ensures we get test coverage + // and enables the use of delve as a debugger. + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // this is needed so Terraform doesn't default to expecting protocol 4; + // we're skipping the handshake because Terraform didn't launch the + // plugins. + os.Setenv("PLUGIN_PROTOCOL_VERSIONS", "5") + + // Acceptance testing does not need to call checkpoint as the output + // is not accessible, nor desirable if explicitly using + // TF_ACC_TERRAFORM_PATH or TF_ACC_TERRAFORM_VERSION environment variables. + // + // Avoid calling (tfexec.Terraform).SetEnv() as it will stop copying + // os.Environ() and prevents TF_VAR_ environment variable usage. + os.Setenv("CHECKPOINT_DISABLE", "1") + + // Terraform 0.12.X and 0.13.X+ treat namespaceless providers + // differently in terms of what namespace they default to. So we're + // going to set both variations, as we don't know which version of + // Terraform we're talking to. We're also going to allow overriding + // the host or namespace using environment variables. + var namespaces []string + host := "registry.terraform.io" + if v := os.Getenv(EnvTfAccProviderNamespace); v != "" { + namespaces = append(namespaces, v) + } else { + namespaces = append(namespaces, "-", "hashicorp") + } + if v := os.Getenv(EnvTfAccProviderHost); v != "" { + host = v + } + + // schema.Provider have a global stop context that is created outside + // the server context and have their own associated goroutine. Since + // Terraform does not call the StopProvider RPC to stop the server in + // reattach mode, ensure that we save these servers to later call that + // RPC and end those goroutines. + legacyProviderServers := make([]*schema.GRPCProviderServer, 0, len(factories.legacy)) + + // Spin up gRPC servers for every provider factory, start a + // WaitGroup to listen for all of the close channels. + var wg sync.WaitGroup + reattachInfo := map[string]tfexec.ReattachConfig{} + for providerName, factory := range factories.legacy { + // providerName may be returned as terraform-provider-foo, and + // we need just foo. So let's fix that. + providerName = strings.TrimPrefix(providerName, "terraform-provider-") + providerAddress := getProviderAddr(providerName) + + logging.HelperResourceDebug(ctx, "Creating sdkv2 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + provider, err := factory() + if err != nil { + return fmt.Errorf("unable to create provider %q from factory: %w", providerName, err) + } + + logging.HelperResourceDebug(ctx, "Created sdkv2 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + // keep track of the running factory, so we can make sure it's + // shut down. + wg.Add(1) + + grpcProviderServer := schema.NewGRPCProviderServer(provider) + legacyProviderServers = append(legacyProviderServers, grpcProviderServer) + + // Ensure StopProvider is always called when returning early. + defer grpcProviderServer.StopProvider(ctx, nil) //nolint:errcheck // does not return errors + + // configure the settings our plugin will be served with + // the GRPCProviderFunc wraps a non-gRPC provider server + // into a gRPC interface, and the logger just discards logs + // from go-plugin. + opts := &plugin.ServeOpts{ + GRPCProviderFunc: func() tfprotov5.ProviderServer { + return grpcProviderServer + }, + Logger: hclog.New(&hclog.LoggerOptions{ + Name: "plugintest", + Level: hclog.Trace, + Output: io.Discard, + }), + NoLogOutputOverride: true, + UseTFLogSink: t, + ProviderAddr: providerAddress, + } + + logging.HelperResourceDebug(ctx, "Starting sdkv2 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + config, closeCh, err := plugin.DebugServe(ctx, opts) + if err != nil { + return fmt.Errorf("unable to serve provider %q: %w", providerName, err) + } + + logging.HelperResourceDebug(ctx, "Started sdkv2 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + tfexecConfig := tfexec.ReattachConfig{ + Protocol: config.Protocol, + ProtocolVersion: config.ProtocolVersion, + Pid: config.Pid, + Test: config.Test, + Addr: tfexec.ReattachConfigAddr{ + Network: config.Addr.Network, + String: config.Addr.String, + }, + } + + // when the provider exits, remove one from the waitgroup + // so we can track when everything is done + go func(c <-chan struct{}) { + <-c + wg.Done() + }(closeCh) + + // set our provider's reattachinfo in our map, once + // for every namespace that different Terraform versions + // may expect. + for _, ns := range namespaces { + reattachInfo[strings.TrimSuffix(host, "/")+"/"+ + strings.TrimSuffix(ns, "/")+"/"+ + providerName] = tfexecConfig + } + } + + // Now spin up gRPC servers for every protov5 provider factory + // in the same way. + for providerName, factory := range factories.protov5 { + // providerName may be returned as terraform-provider-foo, and + // we need just foo. So let's fix that. + providerName = strings.TrimPrefix(providerName, "terraform-provider-") + providerAddress := getProviderAddr(providerName) + + // If the user has supplied the same provider in both + // ProviderFactories and ProtoV5ProviderFactories, they made a + // mistake and we should exit early. + for _, ns := range namespaces { + reattachString := strings.TrimSuffix(host, "/") + "/" + + strings.TrimSuffix(ns, "/") + "/" + + providerName + if _, ok := reattachInfo[reattachString]; ok { + return fmt.Errorf("Provider %s registered in both TestCase.ProviderFactories and TestCase.ProtoV5ProviderFactories: please use one or the other, or supply a muxed provider to TestCase.ProtoV5ProviderFactories.", providerName) + } + } + + logging.HelperResourceDebug(ctx, "Creating tfprotov5 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + provider, err := factory() + if err != nil { + return fmt.Errorf("unable to create provider %q from factory: %w", providerName, err) + } + + logging.HelperResourceDebug(ctx, "Created tfprotov5 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + // keep track of the running factory, so we can make sure it's + // shut down. + wg.Add(1) + + // configure the settings our plugin will be served with + // the GRPCProviderFunc wraps a non-gRPC provider server + // into a gRPC interface, and the logger just discards logs + // from go-plugin. + opts := &plugin.ServeOpts{ + GRPCProviderFunc: func() tfprotov5.ProviderServer { + return provider + }, + Logger: hclog.New(&hclog.LoggerOptions{ + Name: "plugintest", + Level: hclog.Trace, + Output: io.Discard, + }), + NoLogOutputOverride: true, + UseTFLogSink: t, + ProviderAddr: providerAddress, + } + + logging.HelperResourceDebug(ctx, "Starting tfprotov5 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + config, closeCh, err := plugin.DebugServe(ctx, opts) + if err != nil { + return fmt.Errorf("unable to serve provider %q: %w", providerName, err) + } + + logging.HelperResourceDebug(ctx, "Started tfprotov5 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + tfexecConfig := tfexec.ReattachConfig{ + Protocol: config.Protocol, + ProtocolVersion: config.ProtocolVersion, + Pid: config.Pid, + Test: config.Test, + Addr: tfexec.ReattachConfigAddr{ + Network: config.Addr.Network, + String: config.Addr.String, + }, + } + + // when the provider exits, remove one from the waitgroup + // so we can track when everything is done + go func(c <-chan struct{}) { + <-c + wg.Done() + }(closeCh) + + // set our provider's reattachinfo in our map, once + // for every namespace that different Terraform versions + // may expect. + for _, ns := range namespaces { + reattachString := strings.TrimSuffix(host, "/") + "/" + + strings.TrimSuffix(ns, "/") + "/" + + providerName + reattachInfo[reattachString] = tfexecConfig + } + } + + // Now spin up gRPC servers for every protov6 provider factory + // in the same way. + for providerName, factory := range factories.protov6 { + // providerName may be returned as terraform-provider-foo, and + // we need just foo. So let's fix that. + providerName = strings.TrimPrefix(providerName, "terraform-provider-") + providerAddress := getProviderAddr(providerName) + + // If the user has already registered this provider in + // ProviderFactories or ProtoV5ProviderFactories, they made a + // mistake and we should exit early. + for _, ns := range namespaces { + reattachString := strings.TrimSuffix(host, "/") + "/" + + strings.TrimSuffix(ns, "/") + "/" + + providerName + if _, ok := reattachInfo[reattachString]; ok { + return fmt.Errorf("Provider %s registered in both TestCase.ProtoV6ProviderFactories and either TestCase.ProviderFactories or TestCase.ProtoV5ProviderFactories: please use one of the three, or supply a muxed provider to TestCase.ProtoV5ProviderFactories.", providerName) + } + } + + logging.HelperResourceDebug(ctx, "Creating tfprotov6 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + provider, err := factory() + if err != nil { + return fmt.Errorf("unable to create provider %q from factory: %w", providerName, err) + } + + logging.HelperResourceDebug(ctx, "Created tfprotov6 provider instance", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + // keep track of the running factory, so we can make sure it's + // shut down. + wg.Add(1) + + opts := &plugin.ServeOpts{ + GRPCProviderV6Func: func() tfprotov6.ProviderServer { + return provider + }, + Logger: hclog.New(&hclog.LoggerOptions{ + Name: "plugintest", + Level: hclog.Trace, + Output: io.Discard, + }), + NoLogOutputOverride: true, + UseTFLogSink: t, + ProviderAddr: providerAddress, + } + + logging.HelperResourceDebug(ctx, "Starting tfprotov6 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + config, closeCh, err := plugin.DebugServe(ctx, opts) + if err != nil { + return fmt.Errorf("unable to serve provider %q: %w", providerName, err) + } + + logging.HelperResourceDebug(ctx, "Started tfprotov6 provider instance server", map[string]interface{}{logging.KeyProviderAddress: providerAddress}) + + tfexecConfig := tfexec.ReattachConfig{ + Protocol: config.Protocol, + ProtocolVersion: config.ProtocolVersion, + Pid: config.Pid, + Test: config.Test, + Addr: tfexec.ReattachConfigAddr{ + Network: config.Addr.Network, + String: config.Addr.String, + }, + } + + // when the provider exits, remove one from the waitgroup + // so we can track when everything is done + go func(c <-chan struct{}) { + <-c + wg.Done() + }(closeCh) + + // set our provider's reattachinfo in our map, once + // for every namespace that different Terraform versions + // may expect. + for _, ns := range namespaces { + reattachString := strings.TrimSuffix(host, "/") + "/" + + strings.TrimSuffix(ns, "/") + "/" + + providerName + reattachInfo[reattachString] = tfexecConfig + } + } + + // set the working directory reattach info that will tell Terraform how to + // connect to our various running servers. + wd.SetReattachInfo(ctx, reattachInfo) + + logging.HelperResourceTrace(ctx, "Calling wrapped Terraform CLI command") + + // ok, let's call whatever Terraform command the test was trying to + // call, now that we know it'll attach back to those servers we just + // started. + err := f() + if err != nil { + logging.HelperResourceWarn(ctx, "Error running Terraform CLI command", map[string]interface{}{logging.KeyError: err}) + } + + logging.HelperResourceTrace(ctx, "Called wrapped Terraform CLI command") + logging.HelperResourceDebug(ctx, "Stopping providers") + + // cancel the servers so they'll return. Otherwise, this closeCh won't + // get closed, and we'll hang here. + cancel() + + // For legacy providers, call the StopProvider RPC so the StopContext + // goroutine is cleaned up properly. + for _, legacyProviderServer := range legacyProviderServers { + legacyProviderServer.StopProvider(ctx, nil) //nolint:errcheck // does not return errors + } + + logging.HelperResourceTrace(ctx, "Waiting for providers to stop") + + // wait for the servers to actually shut down; it may take a moment for + // them to clean up, or whatever. + // TODO: add a timeout here? + // PC: do we need one? The test will time out automatically... + wg.Wait() + + logging.HelperResourceTrace(ctx, "Providers have successfully stopped") + + // once we've run the Terraform command, let's remove the reattach + // information from the WorkingDir's environment. The WorkingDir will + // persist until the next call, but the server in the reattach info + // doesn't exist anymore at this point, so the reattach info is no + // longer valid. In theory it should be overwritten in the next call, + // but just to avoid any confusing bug reports, let's just unset the + // environment variable altogether. + wd.UnsetReattachInfo() + + // return any error returned from the orchestration code running + // Terraform commands + return err +} + +func getProviderAddr(name string) string { + host := "registry.terraform.io" + namespace := "hashicorp" + if v := os.Getenv(EnvTfAccProviderNamespace); v != "" { + namespace = v + } + if v := os.Getenv(EnvTfAccProviderHost); v != "" { + host = v + } + return strings.TrimSuffix(host, "/") + "/" + + strings.TrimSuffix(namespace, "/") + "/" + + name +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/state_shim.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/state_shim.go new file mode 100644 index 00000000000..43c809f2ba6 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/state_shim.go @@ -0,0 +1,301 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "encoding/json" + "fmt" + "strconv" + + tfjson "github.com/hashicorp/terraform-json" + + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/addrs" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/tfdiags" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +type shimmedState struct { + state *terraform.State +} + +func shimStateFromJson(jsonState *tfjson.State) (*terraform.State, error) { + state := terraform.NewState() + state.TFVersion = jsonState.TerraformVersion + + if jsonState.Values == nil { + // the state is empty + return state, nil + } + + for key, output := range jsonState.Values.Outputs { + os, err := shimOutputState(output) + if err != nil { + return nil, err + } + state.RootModule().Outputs[key] = os + } + + ss := &shimmedState{state} + err := ss.shimStateModule(jsonState.Values.RootModule) + if err != nil { + return nil, err + } + + return state, nil +} + +func shimOutputState(so *tfjson.StateOutput) (*terraform.OutputState, error) { + os := &terraform.OutputState{ + Sensitive: so.Sensitive, + } + + switch v := so.Value.(type) { + case string: + os.Type = "string" + os.Value = v + return os, nil + case []interface{}: + os.Type = "list" + if len(v) == 0 { + os.Value = v + return os, nil + } + switch firstElem := v[0].(type) { + case string: + elements := make([]interface{}, len(v)) + for i, el := range v { + elements[i] = el.(string) + } + os.Value = elements + case bool: + elements := make([]interface{}, len(v)) + for i, el := range v { + elements[i] = el.(bool) + } + os.Value = elements + // unmarshalled number from JSON will always be json.Number + case json.Number: + elements := make([]interface{}, len(v)) + for i, el := range v { + elements[i] = el.(json.Number) + } + os.Value = elements + case []interface{}: + os.Value = v + case map[string]interface{}: + os.Value = v + default: + return nil, fmt.Errorf("unexpected output list element type: %T", firstElem) + } + return os, nil + case map[string]interface{}: + os.Type = "map" + os.Value = v + return os, nil + case bool: + os.Type = "string" + os.Value = strconv.FormatBool(v) + return os, nil + // unmarshalled number from JSON will always be json.Number + case json.Number: + os.Type = "string" + os.Value = v.String() + return os, nil + } + + return nil, fmt.Errorf("unexpected output type: %T", so.Value) +} + +func (ss *shimmedState) shimStateModule(sm *tfjson.StateModule) error { + var path addrs.ModuleInstance + + if sm.Address == "" { + path = addrs.RootModuleInstance + } else { + var diags tfdiags.Diagnostics + path, diags = addrs.ParseModuleInstanceStr(sm.Address) + if diags.HasErrors() { + return diags.Err() + } + } + + mod := ss.state.AddModule(path) + for _, res := range sm.Resources { + resourceState, err := shimResourceState(res) + if err != nil { + return err + } + + key, err := shimResourceStateKey(res) + if err != nil { + return err + } + + mod.Resources[key] = resourceState + } + + if len(sm.ChildModules) > 0 { + return fmt.Errorf("Modules are not supported. Found %d modules.", + len(sm.ChildModules)) + } + return nil +} + +func shimResourceStateKey(res *tfjson.StateResource) (string, error) { + if res.Index == nil { + return res.Address, nil + } + + var mode terraform.ResourceMode + switch res.Mode { + case tfjson.DataResourceMode: + mode = terraform.DataResourceMode + case tfjson.ManagedResourceMode: + mode = terraform.ManagedResourceMode + default: + return "", fmt.Errorf("unexpected resource mode for %q", res.Address) + } + + var index int + switch idx := res.Index.(type) { + case json.Number: + i, err := idx.Int64() + if err != nil { + return "", fmt.Errorf("unexpected index value (%q) for %q, ", + idx, res.Address) + } + index = int(i) + default: + return "", fmt.Errorf("unexpected index type (%T) for %q, "+ + "for_each is not supported", res.Index, res.Address) + } + + rsk := &terraform.ResourceStateKey{ + Mode: mode, + Type: res.Type, + Name: res.Name, + Index: index, + } + + return rsk.String(), nil +} + +func shimResourceState(res *tfjson.StateResource) (*terraform.ResourceState, error) { + sf := &shimmedFlatmap{} + err := sf.FromMap(res.AttributeValues) + if err != nil { + return nil, err + } + attributes := sf.Flatmap() + + if _, ok := attributes["id"]; !ok { + return nil, fmt.Errorf("no %q found in attributes", "id") + } + + return &terraform.ResourceState{ + Provider: res.ProviderName, + Type: res.Type, + Primary: &terraform.InstanceState{ + ID: attributes["id"], + Attributes: attributes, + Meta: map[string]interface{}{ + "schema_version": int(res.SchemaVersion), + }, + Tainted: res.Tainted, + }, + Dependencies: res.DependsOn, + }, nil +} + +type shimmedFlatmap struct { + m map[string]string +} + +func (sf *shimmedFlatmap) FromMap(attributes map[string]interface{}) error { + if sf.m == nil { + sf.m = make(map[string]string, len(attributes)) + } + + return sf.AddMap("", attributes) +} + +func (sf *shimmedFlatmap) AddMap(prefix string, m map[string]interface{}) error { + for key, value := range m { + k := key + if prefix != "" { + k = fmt.Sprintf("%s.%s", prefix, key) + } + + err := sf.AddEntry(k, value) + if err != nil { + return fmt.Errorf("unable to add map key %q entry: %w", k, err) + } + } + + mapLength := "%" + if prefix != "" { + mapLength = fmt.Sprintf("%s.%s", prefix, "%") + } + + if err := sf.AddEntry(mapLength, strconv.Itoa(len(m))); err != nil { + return fmt.Errorf("unable to add map length %q entry: %w", mapLength, err) + } + + return nil +} + +func (sf *shimmedFlatmap) AddSlice(name string, elements []interface{}) error { + for i, elem := range elements { + key := fmt.Sprintf("%s.%d", name, i) + err := sf.AddEntry(key, elem) + if err != nil { + return fmt.Errorf("unable to add slice key %q entry: %w", key, err) + } + } + + sliceLength := fmt.Sprintf("%s.#", name) + if err := sf.AddEntry(sliceLength, strconv.Itoa(len(elements))); err != nil { + return fmt.Errorf("unable to add slice length %q entry: %w", sliceLength, err) + } + + return nil +} + +func (sf *shimmedFlatmap) AddEntry(key string, value interface{}) error { + switch el := value.(type) { + case nil: + // omit the entry + return nil + case bool: + sf.m[key] = strconv.FormatBool(el) + case json.Number: + sf.m[key] = el.String() + case string: + sf.m[key] = el + case map[string]interface{}: + err := sf.AddMap(key, el) + if err != nil { + return err + } + case []interface{}: + err := sf.AddSlice(key, el) + if err != nil { + return err + } + default: + // This should never happen unless terraform-json + // changes how attributes (types) are represented. + // + // We handle all types which the JSON unmarshaler + // can possibly produce + // https://golang.org/pkg/encoding/json/#Unmarshal + + return fmt.Errorf("%q: unexpected type (%T)", key, el) + } + return nil +} + +func (sf *shimmedFlatmap) Flatmap() map[string]string { + return sf.m +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testcase_providers.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testcase_providers.go new file mode 100644 index 00000000000..9639cb04dfc --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testcase_providers.go @@ -0,0 +1,61 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "fmt" + "strings" +) + +// providerConfig takes the list of providers in a TestCase and returns a +// config with only empty provider blocks. This is useful for Import, where no +// config is provided, but the providers must be defined. +func (c TestCase) providerConfig(_ context.Context, skipProviderBlock bool) string { + var providerBlocks, requiredProviderBlocks strings.Builder + + // [BF] The Providers field handling predates the logic being moved to this + // method. It's not entirely clear to me at this time why this field + // is being used and not the others, but leaving it here just in case + // it does have a special purpose that wasn't being unit tested prior. + for name := range c.Providers { + providerBlocks.WriteString(fmt.Sprintf("provider %q {}\n", name)) + } + + for name, externalProvider := range c.ExternalProviders { + if !skipProviderBlock { + providerBlocks.WriteString(fmt.Sprintf("provider %q {}\n", name)) + } + + if externalProvider.Source == "" && externalProvider.VersionConstraint == "" { + continue + } + + requiredProviderBlocks.WriteString(fmt.Sprintf(" %s = {\n", name)) + + if externalProvider.Source != "" { + requiredProviderBlocks.WriteString(fmt.Sprintf(" source = %q\n", externalProvider.Source)) + } + + if externalProvider.VersionConstraint != "" { + requiredProviderBlocks.WriteString(fmt.Sprintf(" version = %q\n", externalProvider.VersionConstraint)) + } + + requiredProviderBlocks.WriteString(" }\n") + } + + if requiredProviderBlocks.Len() > 0 { + return fmt.Sprintf(` +terraform { + required_providers { +%[1]s + } +} + +%[2]s +`, strings.TrimSuffix(requiredProviderBlocks.String(), "\n"), providerBlocks.String()) + } + + return providerBlocks.String() +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testcase_validate.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testcase_validate.go new file mode 100644 index 00000000000..8eb85a14abf --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testcase_validate.go @@ -0,0 +1,87 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" +) + +// hasProviders returns true if the TestCase has set any of the +// ExternalProviders, ProtoV5ProviderFactories, ProtoV6ProviderFactories, +// ProviderFactories, or Providers fields. +func (c TestCase) hasProviders(_ context.Context) bool { + if len(c.ExternalProviders) > 0 { + return true + } + + if len(c.ProtoV5ProviderFactories) > 0 { + return true + } + + if len(c.ProtoV6ProviderFactories) > 0 { + return true + } + + if len(c.ProviderFactories) > 0 { + return true + } + + if len(c.Providers) > 0 { + return true + } + + return false +} + +// validate ensures the TestCase is valid based on the following criteria: +// +// - No overlapping ExternalProviders and Providers entries +// - No overlapping ExternalProviders and ProviderFactories entries +// - TestStep validations performed by the (TestStep).validate() method. +func (c TestCase) validate(ctx context.Context) error { + logging.HelperResourceTrace(ctx, "Validating TestCase") + + if len(c.Steps) == 0 { + err := fmt.Errorf("TestCase missing Steps") + logging.HelperResourceError(ctx, "TestCase validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + + for name := range c.ExternalProviders { + if _, ok := c.Providers[name]; ok { + err := fmt.Errorf("TestCase provider %q set in both ExternalProviders and Providers", name) + logging.HelperResourceError(ctx, "TestCase validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + + if _, ok := c.ProviderFactories[name]; ok { + err := fmt.Errorf("TestCase provider %q set in both ExternalProviders and ProviderFactories", name) + logging.HelperResourceError(ctx, "TestCase validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + } + + testCaseHasProviders := c.hasProviders(ctx) + + for stepIndex, step := range c.Steps { + stepNumber := stepIndex + 1 // Use 1-based index for humans + stepValidateReq := testStepValidateRequest{ + StepNumber: stepNumber, + TestCaseHasProviders: testCaseHasProviders, + } + + err := step.validate(ctx, stepValidateReq) + + if err != nil { + err := fmt.Errorf("TestStep %d/%d validation error: %w", stepNumber, len(c.Steps), err) + logging.HelperResourceError(ctx, "TestCase validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + } + + return nil +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing.go new file mode 100644 index 00000000000..ac575ed43ce --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing.go @@ -0,0 +1,1524 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "errors" + "flag" + "fmt" + "log" + "os" + "regexp" + "strconv" + "strings" + "time" + + "github.com/mitchellh/go-testing-interface" + + "github.com/hashicorp/terraform-plugin-go/tfprotov5" + "github.com/hashicorp/terraform-plugin-go/tfprotov6" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/addrs" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +// flagSweep is a flag available when running tests on the command line. It +// contains a comma separated list of regions to for the sweeper functions to +// run in. This flag bypasses the normal Test path and instead runs functions designed to +// clean up any leaked resources a testing environment could have created. It is +// a best effort attempt, and relies on Provider authors to implement "Sweeper" +// methods for resources. + +// Adding Sweeper methods with AddTestSweepers will +// construct a list of sweeper funcs to be called here. We iterate through +// regions provided by the sweep flag, and for each region we iterate through the +// tests, and exit on any errors. At time of writing, sweepers are ran +// sequentially, however they can list dependencies to be ran first. We track +// the sweepers that have been ran, so as to not run a sweeper twice for a given +// region. +// +// WARNING: +// Sweepers are designed to be destructive. You should not use the -sweep flag +// in any environment that is not strictly a test environment. Resources will be +// destroyed. + +var flagSweep = flag.String("sweep", "", "List of Regions to run available Sweepers") +var flagSweepAllowFailures = flag.Bool("sweep-allow-failures", false, "Enable to allow Sweeper Tests to continue after failures") +var flagSweepRun = flag.String("sweep-run", "", "Comma separated list of Sweeper Tests to run") +var sweeperFuncs map[string]*Sweeper + +// SweeperFunc is a signature for a function that acts as a sweeper. It +// accepts a string for the region that the sweeper is to be ran in. This +// function must be able to construct a valid client for that region. +type SweeperFunc func(r string) error + +type Sweeper struct { + // Name for sweeper. Must be unique to be ran by the Sweeper Runner + Name string + + // Dependencies list the const names of other Sweeper functions that must be ran + // prior to running this Sweeper. This is an ordered list that will be invoked + // recursively at the helper/resource level + Dependencies []string + + // Sweeper function that when invoked sweeps the Provider of specific + // resources + F SweeperFunc +} + +func init() { + sweeperFuncs = make(map[string]*Sweeper) +} + +// AddTestSweepers function adds a given name and Sweeper configuration +// pair to the internal sweeperFuncs map. Invoke this function to register a +// resource sweeper to be available for running when the -sweep flag is used +// with `go test`. Sweeper names must be unique to help ensure a given sweeper +// is only ran once per run. +func AddTestSweepers(name string, s *Sweeper) { + if _, ok := sweeperFuncs[name]; ok { + log.Fatalf("[ERR] Error adding (%s) to sweeperFuncs: function already exists in map", name) + } + + sweeperFuncs[name] = s +} + +// TestMain adds sweeper functionality to the "go test" command, otherwise +// tests are executed as normal. Most provider acceptance tests are written +// using the Test() function of this package, which imposes its own +// requirements and Terraform CLI behavior. Refer to that function's +// documentation for additional details. +// +// Sweepers enable infrastructure cleanup functions to be included with +// resource definitions, typically so developers can remove all resources of +// that resource type from testing infrastructure in case of failures that +// prevented the normal resource destruction behavior of acceptance tests. +// Use the AddTestSweepers() function to configure available sweepers. +// +// Sweeper flags added to the "go test" command: +// +// -sweep: Comma-separated list of locations/regions to run available sweepers. +// -sweep-allow-failures: Enable to allow other sweepers to run after failures. +// -sweep-run: Comma-separated list of resource type sweepers to run. Defaults +// to all sweepers. +// +// Refer to the Env prefixed constants for environment variables that further +// control testing functionality. +func TestMain(m interface { + Run() int +}) { + flag.Parse() + if *flagSweep != "" { + // parse flagSweep contents for regions to run + regions := strings.Split(*flagSweep, ",") + + // get filtered list of sweepers to run based on sweep-run flag + sweepers := filterSweepers(*flagSweepRun, sweeperFuncs) + + if _, err := runSweepers(regions, sweepers, *flagSweepAllowFailures); err != nil { + os.Exit(1) + } + } else { + exitCode := m.Run() + os.Exit(exitCode) + } +} + +func runSweepers(regions []string, sweepers map[string]*Sweeper, allowFailures bool) (map[string]map[string]error, error) { + var sweeperErrorFound bool + sweeperRunList := make(map[string]map[string]error) + + for _, region := range regions { + region = strings.TrimSpace(region) + + var regionSweeperErrorFound bool + regionSweeperRunList := make(map[string]error) + + start := time.Now() + log.Printf("[DEBUG] Running Sweepers for region (%s):\n", region) + for _, sweeper := range sweepers { + if err := runSweeperWithRegion(region, sweeper, sweepers, regionSweeperRunList, allowFailures); err != nil { + if allowFailures { + continue + } + + sweeperRunList[region] = regionSweeperRunList + return sweeperRunList, fmt.Errorf("sweeper (%s) for region (%s) failed: %s", sweeper.Name, region, err) + } + } + elapsed := time.Since(start) + log.Printf("Completed Sweepers for region (%s) in %s", region, elapsed) + + log.Printf("Sweeper Tests for region (%s) ran successfully:\n", region) + for sweeper, sweeperErr := range regionSweeperRunList { + if sweeperErr == nil { + fmt.Printf("\t- %s\n", sweeper) + } else { + regionSweeperErrorFound = true + } + } + + if regionSweeperErrorFound { + sweeperErrorFound = true + log.Printf("Sweeper Tests for region (%s) ran unsuccessfully:\n", region) + for sweeper, sweeperErr := range regionSweeperRunList { + if sweeperErr != nil { + fmt.Printf("\t- %s: %s\n", sweeper, sweeperErr) + } + } + } + + sweeperRunList[region] = regionSweeperRunList + } + + if sweeperErrorFound { + return sweeperRunList, errors.New("at least one sweeper failed") + } + + return sweeperRunList, nil +} + +// filterSweepers takes a comma separated string listing the names of sweepers +// to be ran, and returns a filtered set from the list of all of sweepers to +// run based on the names given. +func filterSweepers(f string, source map[string]*Sweeper) map[string]*Sweeper { + filterSlice := strings.Split(strings.ToLower(f), ",") + if len(filterSlice) == 1 && filterSlice[0] == "" { + // if the filter slice is a single element of "" then no sweeper list was + // given, so just return the full list + return source + } + + sweepers := make(map[string]*Sweeper) + for name := range source { + for _, s := range filterSlice { + if strings.Contains(strings.ToLower(name), s) { + for foundName, foundSweeper := range filterSweeperWithDependencies(name, source) { + sweepers[foundName] = foundSweeper + } + } + } + } + return sweepers +} + +// filterSweeperWithDependencies recursively returns sweeper and all dependencies. +// Since filterSweepers performs fuzzy matching, this function is used +// to perform exact sweeper and dependency lookup. +func filterSweeperWithDependencies(name string, source map[string]*Sweeper) map[string]*Sweeper { + result := make(map[string]*Sweeper) + + currentSweeper, ok := source[name] + if !ok { + log.Printf("[WARN] Sweeper has dependency (%s), but that sweeper was not found", name) + return result + } + + result[name] = currentSweeper + + for _, dependency := range currentSweeper.Dependencies { + for foundName, foundSweeper := range filterSweeperWithDependencies(dependency, source) { + result[foundName] = foundSweeper + } + } + + return result +} + +// runSweeperWithRegion receives a sweeper and a region, and recursively calls +// itself with that region for every dependency found for that sweeper. If there +// are no dependencies, invoke the contained sweeper fun with the region, and +// add the success/fail status to the sweeperRunList. +func runSweeperWithRegion(region string, s *Sweeper, sweepers map[string]*Sweeper, sweeperRunList map[string]error, allowFailures bool) error { + for _, dep := range s.Dependencies { + depSweeper, ok := sweepers[dep] + + if !ok { + log.Printf("[ERROR] Sweeper (%s) has dependency (%s), but that sweeper was not found", s.Name, dep) + return fmt.Errorf("sweeper (%s) has dependency (%s), but that sweeper was not found", s.Name, dep) + } + + log.Printf("[DEBUG] Sweeper (%s) has dependency (%s), running..", s.Name, dep) + err := runSweeperWithRegion(region, depSweeper, sweepers, sweeperRunList, allowFailures) + + if err != nil { + if allowFailures { + log.Printf("[ERROR] Error running Sweeper (%s) in region (%s): %s", depSweeper.Name, region, err) + continue + } + + return err + } + } + + if _, ok := sweeperRunList[s.Name]; ok { + log.Printf("[DEBUG] Sweeper (%s) already ran in region (%s)", s.Name, region) + return nil + } + + log.Printf("[DEBUG] Running Sweeper (%s) in region (%s)", s.Name, region) + + start := time.Now() + runE := s.F(region) + elapsed := time.Since(start) + + log.Printf("[DEBUG] Completed Sweeper (%s) in region (%s) in %s", s.Name, region, elapsed) + + sweeperRunList[s.Name] = runE + + if runE != nil { + log.Printf("[ERROR] Error running Sweeper (%s) in region (%s): %s", s.Name, region, runE) + } + + return runE +} + +// Deprecated: Use EnvTfAcc instead. +const TestEnvVar = EnvTfAcc + +// TestCheckFunc is the callback type used with acceptance tests to check +// the state of a resource. The state passed in is the latest state known, +// or in the case of being after a destroy, it is the last known state when +// it was created. +type TestCheckFunc func(*terraform.State) error + +// ImportStateCheckFunc is the check function for ImportState tests +type ImportStateCheckFunc func([]*terraform.InstanceState) error + +// ImportStateIdFunc is an ID generation function to help with complex ID +// generation for ImportState tests. +type ImportStateIdFunc func(*terraform.State) (string, error) + +// ErrorCheckFunc is a function providers can use to handle errors. +type ErrorCheckFunc func(error) error + +// TestCase is a single acceptance test case used to test the apply/destroy +// lifecycle of a resource in a specific configuration. +// +// When the destroy plan is executed, the config from the last TestStep +// is used to plan it. +// +// Refer to the Env prefixed constants for environment variables that further +// control testing functionality. +type TestCase struct { + // IsUnitTest allows a test to run regardless of the TF_ACC + // environment variable. This should be used with care - only for + // fast tests on local resources (e.g. remote state with a local + // backend) but can be used to increase confidence in correct + // operation of Terraform without waiting for a full acctest run. + IsUnitTest bool + + // PreCheck, if non-nil, will be called before any test steps are + // executed. It will only be executed in the case that the steps + // would run, so it can be used for some validation before running + // acceptance tests, such as verifying that keys are setup. + PreCheck func() + + // ProviderFactories can be specified for the providers that are valid. + // + // This can also be specified at the TestStep level to enable per-step + // differences in providers, however all provider specifications must + // be done either at the TestCase level or TestStep level, otherwise the + // testing framework will raise an error and fail the test. + // + // These are the providers that can be referenced within the test. Each key + // is an individually addressable provider. Typically you will only pass a + // single value here for the provider you are testing. Aliases are not + // supported by the test framework, so to use multiple provider instances, + // you should add additional copies to this map with unique names. To set + // their configuration, you would reference them similar to the following: + // + // provider "my_factory_key" { + // # ... + // } + // + // resource "my_resource" "mr" { + // provider = my_factory_key + // + // # ... + // } + ProviderFactories map[string]func() (*schema.Provider, error) + + // ProtoV5ProviderFactories serves the same purpose as ProviderFactories, + // but for protocol v5 providers defined using the terraform-plugin-go + // ProviderServer interface. + // + // This can also be specified at the TestStep level to enable per-step + // differences in providers, however all provider specifications must + // be done either at the TestCase level or TestStep level, otherwise the + // testing framework will raise an error and fail the test. + ProtoV5ProviderFactories map[string]func() (tfprotov5.ProviderServer, error) + + // ProtoV6ProviderFactories serves the same purpose as ProviderFactories, + // but for protocol v6 providers defined using the terraform-plugin-go + // ProviderServer interface. + // The version of Terraform used in acceptance testing must be greater + // than or equal to v0.15.4 to use ProtoV6ProviderFactories. + // + // This can also be specified at the TestStep level to enable per-step + // differences in providers, however all provider specifications must + // be done either at the TestCase level or TestStep level, otherwise the + // testing framework will raise an error and fail the test. + ProtoV6ProviderFactories map[string]func() (tfprotov6.ProviderServer, error) + + // Providers is the ResourceProvider that will be under test. + // + // Deprecated: Providers is deprecated, please use ProviderFactories + Providers map[string]*schema.Provider + + // ExternalProviders are providers the TestCase relies on that should + // be downloaded from the registry during init. + // + // This can also be specified at the TestStep level to enable per-step + // differences in providers, however all provider specifications must + // be done either at the TestCase level or TestStep level, otherwise the + // testing framework will raise an error and fail the test. + // + // This is generally unnecessary to set at the TestCase level, however + // it has existing in the testing framework prior to the introduction of + // TestStep level specification and was only necessary for performing + // import testing where the configuration contained a provider outside the + // one under test. + ExternalProviders map[string]ExternalProvider + + // PreventPostDestroyRefresh can be set to true for cases where data sources + // are tested alongside real resources + PreventPostDestroyRefresh bool + + // CheckDestroy is called after the resource is finally destroyed + // to allow the tester to test that the resource is truly gone. + CheckDestroy TestCheckFunc + + // ErrorCheck allows providers the option to handle errors such as skipping + // tests based on certain errors. + ErrorCheck ErrorCheckFunc + + // Steps are the apply sequences done within the context of the + // same state. Each step can have its own check to verify correctness. + Steps []TestStep + + // IDRefreshName is the name of the resource to check during ID-only + // refresh testing, which ensures that a resource can be refreshed solely + // by its identifier. This will default to the first non-nil primary + // resource in the state. It runs every TestStep. + // + // While not deprecated, most resource tests should instead prefer using + // TestStep.ImportState based testing as it works with multiple attribute + // identifiers and also verifies resource import functionality. + IDRefreshName string + + // IDRefreshIgnore is a list of configuration keys that will be ignored + // during ID-only refresh testing. + IDRefreshIgnore []string +} + +// ExternalProvider holds information about third-party providers that should +// be downloaded by Terraform as part of running the test step. +type ExternalProvider struct { + VersionConstraint string // the version constraint for the provider + Source string // the provider source +} + +// TestStep is a single apply sequence of a test, done within the +// context of a state. +// +// Multiple TestSteps can be sequenced in a Test to allow testing +// potentially complex update logic. In general, simply create/destroy +// tests will only need one step. +// +// Refer to the Env prefixed constants for environment variables that further +// control testing functionality. +type TestStep struct { + // ResourceName should be set to the name of the resource + // that is being tested. Example: "aws_instance.foo". Various test + // modes use this to auto-detect state information. + // + // This is only required if the test mode settings below say it is + // for the mode you're using. + ResourceName string + + // PreConfig is called before the Config is applied to perform any per-step + // setup that needs to happen. This is called regardless of "test mode" + // below. + PreConfig func() + + // Taint is a list of resource addresses to taint prior to the execution of + // the step. Be sure to only include this at a step where the referenced + // address will be present in state, as it will fail the test if the resource + // is missing. + // + // This option is ignored on ImportState tests, and currently only works for + // resources in the root module path. + Taint []string + + //--------------------------------------------------------------- + // Test modes. One of the following groups of settings must be + // set to determine what the test step will do. Ideally we would've + // used Go interfaces here but there are now hundreds of tests we don't + // want to re-type so instead we just determine which step logic + // to run based on what settings below are set. + //--------------------------------------------------------------- + + //--------------------------------------------------------------- + // Plan, Apply testing + //--------------------------------------------------------------- + + // Config a string of the configuration to give to Terraform. If this + // is set, then the TestCase will execute this step with the same logic + // as a `terraform apply`. + // + // JSON Configuration Syntax can be used and is assumed whenever Config + // contains valid JSON. + Config string + + // Check is called after the Config is applied. Use this step to + // make your own API calls to check the status of things, and to + // inspect the format of the ResourceState itself. + // + // If an error is returned, the test will fail. In this case, a + // destroy plan will still be attempted. + // + // If this is nil, no check is done on this step. + Check TestCheckFunc + + // Destroy will create a destroy plan if set to true. + Destroy bool + + // ExpectNonEmptyPlan can be set to true for specific types of tests that are + // looking to verify that a diff occurs + ExpectNonEmptyPlan bool + + // ExpectError allows the construction of test cases that we expect to fail + // with an error. The specified regexp must match against the error for the + // test to pass. + ExpectError *regexp.Regexp + + // PlanOnly can be set to only run `plan` with this configuration, and not + // actually apply it. This is useful for ensuring config changes result in + // no-op plans + PlanOnly bool + + // PreventDiskCleanup can be set to true for testing terraform modules which + // require access to disk at runtime. Note that this will leave files in the + // temp folder + PreventDiskCleanup bool + + // PreventPostDestroyRefresh can be set to true for cases where data sources + // are tested alongside real resources + PreventPostDestroyRefresh bool + + // SkipFunc enables skipping the TestStep, based on environment criteria. + // For example, this can prevent running certain steps that may be runtime + // platform or API configuration dependent. + // + // Return true with no error to skip the test step. The error return + // should be used to signify issues that prevented the function from + // completing as expected. + // + // SkipFunc is called after PreConfig but before applying the Config. + SkipFunc func() (bool, error) + + //--------------------------------------------------------------- + // ImportState testing + //--------------------------------------------------------------- + + // ImportState, if true, will test the functionality of ImportState + // by importing the resource with ResourceName (must be set) and the + // ID of that resource. + ImportState bool + + // ImportStateId is the ID to perform an ImportState operation with. + // This is optional. If it isn't set, then the resource ID is automatically + // determined by inspecting the state for ResourceName's ID. + ImportStateId string + + // ImportStateIdPrefix is the prefix added in front of ImportStateId. + // This can be useful in complex import cases, where more than one + // attribute needs to be passed on as the Import ID. Mainly in cases + // where the ID is not known, and a known prefix needs to be added to + // the unset ImportStateId field. + ImportStateIdPrefix string + + // ImportStateIdFunc is a function that can be used to dynamically generate + // the ID for the ImportState tests. It is sent the state, which can be + // checked to derive the attributes necessary and generate the string in the + // desired format. + ImportStateIdFunc ImportStateIdFunc + + // ImportStateCheck checks the results of ImportState. It should be + // used to verify that the resulting value of ImportState has the + // proper resources, IDs, and attributes. + // + // Prefer ImportStateVerify over ImportStateCheck, unless the resource + // import explicitly is expected to create multiple resources (not a + // recommended resource implementation) or if attributes are imported with + // syntactically different but semantically/functionally equivalent values + // where special logic is needed. + // + // Terraform versions 1.3 and later can include data source states during + // import, which the testing framework will skip to prevent the need for + // Terraform version specific logic in provider testing. + ImportStateCheck ImportStateCheckFunc + + // ImportStateVerify, if true, will also check that the state values + // that are finally put into the state after import match for all the + // IDs returned by the Import. Note that this checks for strict equality + // and does not respect DiffSuppressFunc or CustomizeDiff. + // + // ImportStateVerifyIgnore is a list of prefixes of fields that should + // not be verified to be equal. These can be set to ephemeral fields or + // fields that can't be refreshed and don't matter. + ImportStateVerify bool + ImportStateVerifyIgnore []string + + // ImportStatePersist, if true, will update the persisted state with the + // state generated by the import operation (i.e., terraform import). When + // false (default) the state generated by the import operation is discarded + // at the end of the test step that is verifying import behavior. + ImportStatePersist bool + + //--------------------------------------------------------------- + // RefreshState testing + //--------------------------------------------------------------- + + // RefreshState, if true, will test the functionality of `terraform + // refresh` by refreshing the state, running any checks against the + // refreshed state, and running a plan to verify against unexpected plan + // differences. + // + // If the refresh is expected to result in a non-empty plan + // ExpectNonEmptyPlan should be set to true in the same TestStep. + // + // RefreshState cannot be the first TestStep and, it is mutually exclusive + // with ImportState. + RefreshState bool + + // ProviderFactories can be specified for the providers that are valid for + // this TestStep. When providers are specified at the TestStep level, all + // TestStep within a TestCase must declare providers. + // + // This can also be specified at the TestCase level for all TestStep, + // however all provider specifications must be done either at the TestCase + // level or TestStep level, otherwise the testing framework will raise an + // error and fail the test. + // + // These are the providers that can be referenced within the test. Each key + // is an individually addressable provider. Typically you will only pass a + // single value here for the provider you are testing. Aliases are not + // supported by the test framework, so to use multiple provider instances, + // you should add additional copies to this map with unique names. To set + // their configuration, you would reference them similar to the following: + // + // provider "my_factory_key" { + // # ... + // } + // + // resource "my_resource" "mr" { + // provider = my_factory_key + // + // # ... + // } + ProviderFactories map[string]func() (*schema.Provider, error) + + // ProtoV5ProviderFactories serves the same purpose as ProviderFactories, + // but for protocol v5 providers defined using the terraform-plugin-go + // ProviderServer interface. When providers are specified at the TestStep + // level, all TestStep within a TestCase must declare providers. + // + // This can also be specified at the TestCase level for all TestStep, + // however all provider specifications must be done either at the TestCase + // level or TestStep level, otherwise the testing framework will raise an + // error and fail the test. + ProtoV5ProviderFactories map[string]func() (tfprotov5.ProviderServer, error) + + // ProtoV6ProviderFactories serves the same purpose as ProviderFactories, + // but for protocol v6 providers defined using the terraform-plugin-go + // ProviderServer interface. + // The version of Terraform used in acceptance testing must be greater + // than or equal to v0.15.4 to use ProtoV6ProviderFactories. When providers + // are specified at the TestStep level, all TestStep within a TestCase must + // declare providers. + // + // This can also be specified at the TestCase level for all TestStep, + // however all provider specifications must be done either at the TestCase + // level or TestStep level, otherwise the testing framework will raise an + // error and fail the test. + ProtoV6ProviderFactories map[string]func() (tfprotov6.ProviderServer, error) + + // ExternalProviders are providers the TestStep relies on that should + // be downloaded from the registry during init. When providers are + // specified at the TestStep level, all TestStep within a TestCase must + // declare providers. + // + // This can also be specified at the TestCase level for all TestStep, + // however all provider specifications must be done either at the TestCase + // level or TestStep level, otherwise the testing framework will raise an + // error and fail the test. + // + // Outside specifying an earlier version of the provider under test, + // typically for state upgrader testing, this is generally only necessary + // for performing import testing where the prior TestStep configuration + // contained a provider outside the one under test. + ExternalProviders map[string]ExternalProvider +} + +// ParallelTest performs an acceptance test on a resource, allowing concurrency +// with other ParallelTest. The number of concurrent tests is controlled by the +// "go test" command -parallel flag. +// +// Tests will fail if they do not properly handle conditions to allow multiple +// tests to occur against the same resource or service (e.g. random naming). +// +// Test() function requirements and documentation also apply to this function. +func ParallelTest(t testing.T, c TestCase) { + t.Helper() + t.Parallel() + Test(t, c) +} + +// Test performs an acceptance test on a resource. +// +// Tests are not run unless an environmental variable "TF_ACC" is +// set to some non-empty value. This is to avoid test cases surprising +// a user by creating real resources. +// +// Tests will fail unless the verbose flag (`go test -v`, or explicitly +// the "-test.v" flag) is set. Because some acceptance tests take quite +// long, we require the verbose flag so users are able to see progress +// output. +// +// Use the ParallelTest() function to automatically set (*testing.T).Parallel() +// to enable testing concurrency. Use the UnitTest() function to automatically +// set the TestCase type IsUnitTest field. +// +// This function will automatically find or install Terraform CLI into a +// temporary directory, based on the following behavior: +// +// - If the TF_ACC_TERRAFORM_PATH environment variable is set, that +// Terraform CLI binary is used if found and executable. If not found or +// executable, an error will be returned unless the +// TF_ACC_TERRAFORM_VERSION environment variable is also set. +// - If the TF_ACC_TERRAFORM_VERSION environment variable is set, install +// and use that Terraform CLI version. +// - If both the TF_ACC_TERRAFORM_PATH and TF_ACC_TERRAFORM_VERSION +// environment variables are unset, perform a lookup for the Terraform +// CLI binary based on the operating system PATH. If not found, the +// latest available Terraform CLI binary is installed. +// +// Refer to the Env prefixed constants for additional details about these +// environment variables, and others, that control testing functionality. +func Test(t testing.T, c TestCase) { + t.Helper() + + ctx := context.Background() + ctx = logging.InitTestContext(ctx, t) + + err := c.validate(ctx) + + if err != nil { + logging.HelperResourceError(ctx, + "Test validation error", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("Test validation error: %s", err) + } + + // We only run acceptance tests if an env var is set because they're + // slow and generally require some outside configuration. You can opt out + // of this with OverrideEnvVar on individual TestCases. + if os.Getenv(EnvTfAcc) == "" && !c.IsUnitTest { + t.Skip(fmt.Sprintf( + "Acceptance tests skipped unless env '%s' set", + EnvTfAcc)) + return + } + + // Copy any explicitly passed providers to factories, this is for backwards compatibility. + if len(c.Providers) > 0 { + c.ProviderFactories = map[string]func() (*schema.Provider, error){} + + for name, p := range c.Providers { + prov := p + c.ProviderFactories[name] = func() (*schema.Provider, error) { //nolint:unparam // required signature + return prov, nil + } + } + } + + logging.HelperResourceDebug(ctx, "Starting TestCase") + + // Run the PreCheck if we have it. + // This is done after the auto-configure to allow providers + // to override the default auto-configure parameters. + if c.PreCheck != nil { + logging.HelperResourceDebug(ctx, "Calling TestCase PreCheck") + + c.PreCheck() + + logging.HelperResourceDebug(ctx, "Called TestCase PreCheck") + } + + sourceDir, err := os.Getwd() + if err != nil { + t.Fatalf("Error getting working dir: %s", err) + } + helper := plugintest.AutoInitProviderHelper(ctx, sourceDir) + defer func(helper *plugintest.Helper) { + err := helper.Close() + if err != nil { + logging.HelperResourceError(ctx, "Unable to clean up temporary test files", map[string]interface{}{logging.KeyError: err}) + } + }(helper) + + runNewTest(ctx, t, c, helper) + + logging.HelperResourceDebug(ctx, "Finished TestCase") +} + +// UnitTest is a helper to force the acceptance testing harness to run in the +// normal unit test suite. This should only be used for resource that don't +// have any external dependencies. +// +// Test() function requirements and documentation also apply to this function. +func UnitTest(t testing.T, c TestCase) { + t.Helper() + + c.IsUnitTest = true + Test(t, c) +} + +func testResource(c TestStep, state *terraform.State) (*terraform.ResourceState, error) { + for _, m := range state.Modules { + if len(m.Resources) > 0 { + if v, ok := m.Resources[c.ResourceName]; ok { + return v, nil + } + } + } + + return nil, fmt.Errorf( + "Resource specified by ResourceName couldn't be found: %s", c.ResourceName) +} + +// ComposeTestCheckFunc lets you compose multiple TestCheckFuncs into +// a single TestCheckFunc. +// +// As a user testing their provider, this lets you decompose your checks +// into smaller pieces more easily. +// +// ComposeTestCheckFunc returns immediately on the first TestCheckFunc error. +// To aggregate all errors, use ComposeAggregateTestCheckFunc instead. +func ComposeTestCheckFunc(fs ...TestCheckFunc) TestCheckFunc { + return func(s *terraform.State) error { + for i, f := range fs { + if err := f(s); err != nil { + return fmt.Errorf("Check %d/%d error: %s", i+1, len(fs), err) + } + } + + return nil + } +} + +// ComposeAggregateTestCheckFunc lets you compose multiple TestCheckFuncs into +// a single TestCheckFunc. +// +// As a user testing their provider, this lets you decompose your checks +// into smaller pieces more easily. +// +// Unlike ComposeTestCheckFunc, ComposeAggregateTestCheckFunc runs _all_ of the +// TestCheckFuncs and aggregates failures. +func ComposeAggregateTestCheckFunc(fs ...TestCheckFunc) TestCheckFunc { + return func(s *terraform.State) error { + var result []error + + for i, f := range fs { + if err := f(s); err != nil { + result = append(result, fmt.Errorf("Check %d/%d error: %w", i+1, len(fs), err)) + } + } + + return errors.Join(result...) + } +} + +// TestCheckResourceAttrSet ensures any value exists in the state for the +// given name and key combination. The opposite of this TestCheckFunc is +// TestCheckNoResourceAttr. State value checking is only recommended for +// testing Computed attributes and attribute defaults. +// +// Use this as a last resort when a more specific TestCheckFunc cannot be +// implemented, such as: +// +// - TestCheckResourceAttr: Equality checking of non-TypeSet state value. +// - TestCheckResourceAttrPair: Equality checking of non-TypeSet state +// value, based on another state value. +// - TestCheckTypeSet*: Equality checking of TypeSet state values. +// - TestMatchResourceAttr: Regular expression checking of non-TypeSet +// state value. +// - TestMatchTypeSet*: Regular expression checking on TypeSet state values. +// +// For managed resources, the name parameter is combination of the resource +// type, a period (.), and the name label. The name for the below example +// configuration would be "myprovider_thing.example". +// +// resource "myprovider_thing" "example" { ... } +// +// For data sources, the name parameter is a combination of the keyword "data", +// a period (.), the data source type, a period (.), and the name label. The +// name for the below example configuration would be +// "data.myprovider_thing.example". +// +// data "myprovider_thing" "example" { ... } +// +// The key parameter is an attribute path in Terraform CLI 0.11 and earlier +// "flatmap" syntax. Keys start with the attribute name of a top-level +// attribute. Use the following special key syntax to inspect underlying +// values of a list or map attribute: +// +// - .{NUMBER}: List value at index, e.g. .0 to inspect the first element +// - .{KEY}: Map value at key, e.g. .example to inspect the example key +// value +// +// While it is possible to check nested attributes under list and map +// attributes using the special key syntax, checking a list, map, or set +// attribute directly is not supported. Use TestCheckResourceAttr with +// the special .# or .% key syntax for those situations instead. +func TestCheckResourceAttrSet(name, key string) TestCheckFunc { + return checkIfIndexesIntoTypeSet(key, func(s *terraform.State) error { + is, err := primaryInstanceState(s, name) + if err != nil { + return err + } + + return testCheckResourceAttrSet(is, name, key) + }) +} + +// TestCheckModuleResourceAttrSet - as per TestCheckResourceAttrSet but with +// support for non-root modules +func TestCheckModuleResourceAttrSet(mp []string, name string, key string) TestCheckFunc { + mpt := addrs.Module(mp).UnkeyedInstanceShim() + return checkIfIndexesIntoTypeSet(key, func(s *terraform.State) error { + is, err := modulePathPrimaryInstanceState(s, mpt, name) + if err != nil { + return err + } + + return testCheckResourceAttrSet(is, name, key) + }) +} + +func testCheckResourceAttrSet(is *terraform.InstanceState, name string, key string) error { + val, ok := is.Attributes[key] + + if ok && val != "" { + return nil + } + + if _, ok := is.Attributes[key+".#"]; ok { + return fmt.Errorf( + "%s: list or set attribute '%s' must be checked by element count key (%s) or element value keys (e.g. %s). Set element value checks should use TestCheckTypeSet functions instead.", + name, + key, + key+".#", + key+".0", + ) + } + + if _, ok := is.Attributes[key+".%"]; ok { + return fmt.Errorf( + "%s: map attribute '%s' must be checked by element count key (%s) or element value keys (e.g. %s).", + name, + key, + key+".%", + key+".examplekey", + ) + } + + return fmt.Errorf("%s: Attribute '%s' expected to be set", name, key) +} + +// TestCheckResourceAttr ensures a specific value is stored in state for the +// given name and key combination. State value checking is only recommended for +// testing Computed attributes and attribute defaults. +// +// For managed resources, the name parameter is combination of the resource +// type, a period (.), and the name label. The name for the below example +// configuration would be "myprovider_thing.example". +// +// resource "myprovider_thing" "example" { ... } +// +// For data sources, the name parameter is a combination of the keyword "data", +// a period (.), the data source type, a period (.), and the name label. The +// name for the below example configuration would be +// "data.myprovider_thing.example". +// +// data "myprovider_thing" "example" { ... } +// +// The key parameter is an attribute path in Terraform CLI 0.11 and earlier +// "flatmap" syntax. Keys start with the attribute name of a top-level +// attribute. Use the following special key syntax to inspect list, map, and +// set attributes: +// +// - .{NUMBER}: List value at index, e.g. .0 to inspect the first element. +// Use the TestCheckTypeSet* and TestMatchTypeSet* functions instead +// for sets. +// - .{KEY}: Map value at key, e.g. .example to inspect the example key +// value. +// - .#: Number of elements in list or set. +// - .%: Number of elements in map. +// +// The value parameter is the stringified data to check at the given key. Use +// the following attribute type rules to set the value: +// +// - Boolean: "false" or "true". +// - Float/Integer: Stringified number, such as "1.2" or "123". +// - String: No conversion necessary. +func TestCheckResourceAttr(name, key, value string) TestCheckFunc { + return checkIfIndexesIntoTypeSet(key, func(s *terraform.State) error { + is, err := primaryInstanceState(s, name) + if err != nil { + return err + } + + return testCheckResourceAttr(is, name, key, value) + }) +} + +// TestCheckModuleResourceAttr - as per TestCheckResourceAttr but with +// support for non-root modules +func TestCheckModuleResourceAttr(mp []string, name string, key string, value string) TestCheckFunc { + mpt := addrs.Module(mp).UnkeyedInstanceShim() + return checkIfIndexesIntoTypeSet(key, func(s *terraform.State) error { + is, err := modulePathPrimaryInstanceState(s, mpt, name) + if err != nil { + return err + } + + return testCheckResourceAttr(is, name, key, value) + }) +} + +func testCheckResourceAttr(is *terraform.InstanceState, name string, key string, value string) error { + v, ok := is.Attributes[key] + + if !ok { + // Empty containers may be elided from the state. + // If the intent here is to check for an empty container, allow the key to + // also be non-existent. + if value == "0" && (strings.HasSuffix(key, ".#") || strings.HasSuffix(key, ".%")) { + return nil + } + + if _, ok := is.Attributes[key+".#"]; ok { + return fmt.Errorf( + "%s: list or set attribute '%s' must be checked by element count key (%s) or element value keys (e.g. %s). Set element value checks should use TestCheckTypeSet functions instead.", + name, + key, + key+".#", + key+".0", + ) + } + + if _, ok := is.Attributes[key+".%"]; ok { + return fmt.Errorf( + "%s: map attribute '%s' must be checked by element count key (%s) or element value keys (e.g. %s).", + name, + key, + key+".%", + key+".examplekey", + ) + } + + return fmt.Errorf("%s: Attribute '%s' not found", name, key) + } + + if v != value { + return fmt.Errorf( + "%s: Attribute '%s' expected %#v, got %#v", + name, + key, + value, + v) + } + + return nil +} + +// CheckResourceAttrWithFunc is the callback type used to apply a custom checking logic +// when using TestCheckResourceAttrWith and a value is found for the given name and key. +// +// When this function returns an error, TestCheckResourceAttrWith will fail the check. +type CheckResourceAttrWithFunc func(value string) error + +// TestCheckResourceAttrWith ensures a value stored in state for the +// given name and key combination, is checked against a custom logic. +// State value checking is only recommended for testing Computed attributes +// and attribute defaults. +// +// For managed resources, the name parameter is combination of the resource +// type, a period (.), and the name label. The name for the below example +// configuration would be "myprovider_thing.example". +// +// resource "myprovider_thing" "example" { ... } +// +// For data sources, the name parameter is a combination of the keyword "data", +// a period (.), the data source type, a period (.), and the name label. The +// name for the below example configuration would be +// "data.myprovider_thing.example". +// +// data "myprovider_thing" "example" { ... } +// +// The key parameter is an attribute path in Terraform CLI 0.11 and earlier +// "flatmap" syntax. Keys start with the attribute name of a top-level +// attribute. Use the following special key syntax to inspect list, map, and +// set attributes: +// +// - .{NUMBER}: List value at index, e.g. .0 to inspect the first element. +// Use the TestCheckTypeSet* and TestMatchTypeSet* functions instead +// for sets. +// - .{KEY}: Map value at key, e.g. .example to inspect the example key +// value. +// - .#: Number of elements in list or set. +// - .%: Number of elements in map. +// +// The checkValueFunc parameter is a CheckResourceAttrWithFunc, +// and it's provided with the attribute value to apply a custom checking logic, +// if it was found in the state. The function must return an error for the +// check to fail, or `nil` to succeed. +func TestCheckResourceAttrWith(name, key string, checkValueFunc CheckResourceAttrWithFunc) TestCheckFunc { + return checkIfIndexesIntoTypeSet(key, func(s *terraform.State) error { + is, err := primaryInstanceState(s, name) + if err != nil { + return err + } + + err = testCheckResourceAttrSet(is, name, key) + if err != nil { + return err + } + + err = checkValueFunc(is.Attributes[key]) + if err != nil { + return fmt.Errorf("%s: Attribute %q value: %w", name, key, err) + } + + return nil + }) +} + +// TestCheckNoResourceAttr ensures no value exists in the state for the +// given name and key combination. The opposite of this TestCheckFunc is +// TestCheckResourceAttrSet. State value checking is only recommended for +// testing Computed attributes and attribute defaults. +// +// For managed resources, the name parameter is combination of the resource +// type, a period (.), and the name label. The name for the below example +// configuration would be "myprovider_thing.example". +// +// resource "myprovider_thing" "example" { ... } +// +// For data sources, the name parameter is a combination of the keyword "data", +// a period (.), the data source type, a period (.), and the name label. The +// name for the below example configuration would be +// "data.myprovider_thing.example". +// +// data "myprovider_thing" "example" { ... } +// +// The key parameter is an attribute path in Terraform CLI 0.11 and earlier +// "flatmap" syntax. Keys start with the attribute name of a top-level +// attribute. Use the following special key syntax to inspect underlying +// values of a list or map attribute: +// +// - .{NUMBER}: List value at index, e.g. .0 to inspect the first element. +// - .{KEY}: Map value at key, e.g. .example to inspect the example key +// value. +// +// While it is possible to check nested attributes under list and map +// attributes using the special key syntax, checking a list, map, or set +// attribute directly is not supported. Use TestCheckResourceAttr with +// the special .# or .% key syntax for those situations instead. +func TestCheckNoResourceAttr(name, key string) TestCheckFunc { + return checkIfIndexesIntoTypeSet(key, func(s *terraform.State) error { + is, err := primaryInstanceState(s, name) + if err != nil { + return err + } + + return testCheckNoResourceAttr(is, name, key) + }) +} + +// TestCheckModuleNoResourceAttr - as per TestCheckNoResourceAttr but with +// support for non-root modules +func TestCheckModuleNoResourceAttr(mp []string, name string, key string) TestCheckFunc { + mpt := addrs.Module(mp).UnkeyedInstanceShim() + return checkIfIndexesIntoTypeSet(key, func(s *terraform.State) error { + is, err := modulePathPrimaryInstanceState(s, mpt, name) + if err != nil { + return err + } + + return testCheckNoResourceAttr(is, name, key) + }) +} + +func testCheckNoResourceAttr(is *terraform.InstanceState, name string, key string) error { + v, ok := is.Attributes[key] + + // Empty containers may sometimes be included in the state. + // If the intent here is to check for an empty container, allow the value to + // also be "0". + if v == "0" && (strings.HasSuffix(key, ".#") || strings.HasSuffix(key, ".%")) { + return nil + } + + if ok { + return fmt.Errorf("%s: Attribute '%s' found when not expected", name, key) + } + + if _, ok := is.Attributes[key+".#"]; ok { + return fmt.Errorf( + "%s: list or set attribute '%s' must be checked by element count key (%s) or element value keys (e.g. %s). Set element value checks should use TestCheckTypeSet functions instead.", + name, + key, + key+".#", + key+".0", + ) + } + + if _, ok := is.Attributes[key+".%"]; ok { + return fmt.Errorf( + "%s: map attribute '%s' must be checked by element count key (%s) or element value keys (e.g. %s).", + name, + key, + key+".%", + key+".examplekey", + ) + } + + return nil +} + +// TestMatchResourceAttr ensures a value matching a regular expression is +// stored in state for the given name and key combination. State value checking +// is only recommended for testing Computed attributes and attribute defaults. +// +// For managed resources, the name parameter is combination of the resource +// type, a period (.), and the name label. The name for the below example +// configuration would be "myprovider_thing.example". +// +// resource "myprovider_thing" "example" { ... } +// +// For data sources, the name parameter is a combination of the keyword "data", +// a period (.), the data source type, a period (.), and the name label. The +// name for the below example configuration would be +// "data.myprovider_thing.example". +// +// data "myprovider_thing" "example" { ... } +// +// The key parameter is an attribute path in Terraform CLI 0.11 and earlier +// "flatmap" syntax. Keys start with the attribute name of a top-level +// attribute. Use the following special key syntax to inspect list, map, and +// set attributes: +// +// - .{NUMBER}: List value at index, e.g. .0 to inspect the first element. +// Use the TestCheckTypeSet* and TestMatchTypeSet* functions instead +// for sets. +// - .{KEY}: Map value at key, e.g. .example to inspect the example key +// value. +// - .#: Number of elements in list or set. +// - .%: Number of elements in map. +// +// The value parameter is a compiled regular expression. A typical pattern is +// using the regexp.MustCompile() function, which will automatically ensure the +// regular expression is supported by the Go regular expression handlers during +// compilation. +func TestMatchResourceAttr(name, key string, r *regexp.Regexp) TestCheckFunc { + return checkIfIndexesIntoTypeSet(key, func(s *terraform.State) error { + is, err := primaryInstanceState(s, name) + if err != nil { + return err + } + + return testMatchResourceAttr(is, name, key, r) + }) +} + +// TestModuleMatchResourceAttr - as per TestMatchResourceAttr but with +// support for non-root modules +func TestModuleMatchResourceAttr(mp []string, name string, key string, r *regexp.Regexp) TestCheckFunc { + mpt := addrs.Module(mp).UnkeyedInstanceShim() + return checkIfIndexesIntoTypeSet(key, func(s *terraform.State) error { + is, err := modulePathPrimaryInstanceState(s, mpt, name) + if err != nil { + return err + } + + return testMatchResourceAttr(is, name, key, r) + }) +} + +func testMatchResourceAttr(is *terraform.InstanceState, name string, key string, r *regexp.Regexp) error { + if !r.MatchString(is.Attributes[key]) { + return fmt.Errorf( + "%s: Attribute '%s' didn't match %q, got %#v", + name, + key, + r.String(), + is.Attributes[key]) + } + + return nil +} + +// TestCheckResourceAttrPtr is like TestCheckResourceAttr except the +// value is a pointer so that it can be updated while the test is running. +// It will only be dereferenced at the point this step is run. +// +// Refer to the TestCheckResourceAttr documentation for more information about +// setting the name, key, and value parameters. +func TestCheckResourceAttrPtr(name string, key string, value *string) TestCheckFunc { + return func(s *terraform.State) error { + return TestCheckResourceAttr(name, key, *value)(s) + } +} + +// TestCheckModuleResourceAttrPtr - as per TestCheckResourceAttrPtr but with +// support for non-root modules +func TestCheckModuleResourceAttrPtr(mp []string, name string, key string, value *string) TestCheckFunc { + return func(s *terraform.State) error { + return TestCheckModuleResourceAttr(mp, name, key, *value)(s) + } +} + +// TestCheckResourceAttrPair ensures value equality in state between the first +// given name and key combination and the second name and key combination. +// State value checking is only recommended for testing Computed attributes +// and attribute defaults. +// +// For managed resources, the name parameter is combination of the resource +// type, a period (.), and the name label. The name for the below example +// configuration would be "myprovider_thing.example". +// +// resource "myprovider_thing" "example" { ... } +// +// For data sources, the name parameter is a combination of the keyword "data", +// a period (.), the data source type, a period (.), and the name label. The +// name for the below example configuration would be +// "data.myprovider_thing.example". +// +// data "myprovider_thing" "example" { ... } +// +// The first and second names may use any combination of managed resources +// and/or data sources. +// +// The key parameter is an attribute path in Terraform CLI 0.11 and earlier +// "flatmap" syntax. Keys start with the attribute name of a top-level +// attribute. Use the following special key syntax to inspect list, map, and +// set attributes: +// +// - .{NUMBER}: List value at index, e.g. .0 to inspect the first element. +// Use the TestCheckTypeSet* and TestMatchTypeSet* functions instead +// for sets. +// - .{KEY}: Map value at key, e.g. .example to inspect the example key +// value. +// - .#: Number of elements in list or set. +// - .%: Number of elements in map. +func TestCheckResourceAttrPair(nameFirst, keyFirst, nameSecond, keySecond string) TestCheckFunc { + return checkIfIndexesIntoTypeSetPair(keyFirst, keySecond, func(s *terraform.State) error { + isFirst, err := primaryInstanceState(s, nameFirst) + if err != nil { + return err + } + + isSecond, err := primaryInstanceState(s, nameSecond) + if err != nil { + return err + } + + return testCheckResourceAttrPair(isFirst, nameFirst, keyFirst, isSecond, nameSecond, keySecond) + }) +} + +// TestCheckModuleResourceAttrPair - as per TestCheckResourceAttrPair but with +// support for non-root modules +func TestCheckModuleResourceAttrPair(mpFirst []string, nameFirst string, keyFirst string, mpSecond []string, nameSecond string, keySecond string) TestCheckFunc { + mptFirst := addrs.Module(mpFirst).UnkeyedInstanceShim() + mptSecond := addrs.Module(mpSecond).UnkeyedInstanceShim() + return checkIfIndexesIntoTypeSetPair(keyFirst, keySecond, func(s *terraform.State) error { + isFirst, err := modulePathPrimaryInstanceState(s, mptFirst, nameFirst) + if err != nil { + return err + } + + isSecond, err := modulePathPrimaryInstanceState(s, mptSecond, nameSecond) + if err != nil { + return err + } + + return testCheckResourceAttrPair(isFirst, nameFirst, keyFirst, isSecond, nameSecond, keySecond) + }) +} + +func testCheckResourceAttrPair(isFirst *terraform.InstanceState, nameFirst string, keyFirst string, isSecond *terraform.InstanceState, nameSecond string, keySecond string) error { + if nameFirst == nameSecond && keyFirst == keySecond { + return fmt.Errorf( + "comparing self: resource %s attribute %s", + nameFirst, + keyFirst, + ) + } + + vFirst, okFirst := isFirst.Attributes[keyFirst] + vSecond, okSecond := isSecond.Attributes[keySecond] + + // Container count values of 0 should not be relied upon, and not reliably + // maintained by helper/schema. For the purpose of tests, consider unset and + // 0 to be equal. + if len(keyFirst) > 2 && len(keySecond) > 2 && keyFirst[len(keyFirst)-2:] == keySecond[len(keySecond)-2:] && + (strings.HasSuffix(keyFirst, ".#") || strings.HasSuffix(keyFirst, ".%")) { + // they have the same suffix, and it is a collection count key. + if vFirst == "0" || vFirst == "" { + okFirst = false + } + if vSecond == "0" || vSecond == "" { + okSecond = false + } + } + + if okFirst != okSecond { + if !okFirst { + return fmt.Errorf("%s: Attribute %q not set, but %q is set in %s as %q", nameFirst, keyFirst, keySecond, nameSecond, vSecond) + } + return fmt.Errorf("%s: Attribute %q is %q, but %q is not set in %s", nameFirst, keyFirst, vFirst, keySecond, nameSecond) + } + if !(okFirst || okSecond) { + // If they both don't exist then they are equally unset, so that's okay. + return nil + } + + if vFirst != vSecond { + return fmt.Errorf( + "%s: Attribute '%s' expected %#v, got %#v", + nameFirst, + keyFirst, + vSecond, + vFirst) + } + + return nil +} + +// TestCheckOutput checks an output in the Terraform configuration +func TestCheckOutput(name, value string) TestCheckFunc { + return func(s *terraform.State) error { + ms := s.RootModule() + rs, ok := ms.Outputs[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + if rs.Value != value { + return fmt.Errorf( + "Output '%s': expected %#v, got %#v", + name, + value, + rs) + } + + return nil + } +} + +func TestMatchOutput(name string, r *regexp.Regexp) TestCheckFunc { + return func(s *terraform.State) error { + ms := s.RootModule() + rs, ok := ms.Outputs[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + if !r.MatchString(rs.Value.(string)) { + return fmt.Errorf( + "Output '%s': %#v didn't match %q", + name, + rs, + r.String()) + } + + return nil + } +} + +// modulePrimaryInstanceState returns the instance state for the given resource +// name in a ModuleState +func modulePrimaryInstanceState(ms *terraform.ModuleState, name string) (*terraform.InstanceState, error) { + rs, ok := ms.Resources[name] + if !ok { + return nil, fmt.Errorf("Not found: %s in %s", name, ms.Path) + } + + is := rs.Primary + if is == nil { + return nil, fmt.Errorf("No primary instance: %s in %s", name, ms.Path) + } + + return is, nil +} + +// modulePathPrimaryInstanceState returns the primary instance state for the +// given resource name in a given module path. +func modulePathPrimaryInstanceState(s *terraform.State, mp addrs.ModuleInstance, name string) (*terraform.InstanceState, error) { + ms := s.ModuleByPath(mp) + if ms == nil { + return nil, fmt.Errorf("No module found at: %s", mp) + } + + return modulePrimaryInstanceState(ms, name) +} + +// primaryInstanceState returns the primary instance state for the given +// resource name in the root module. +func primaryInstanceState(s *terraform.State, name string) (*terraform.InstanceState, error) { + ms := s.RootModule() + return modulePrimaryInstanceState(ms, name) +} + +// indexesIntoTypeSet is a heuristic to try and identify if a flatmap style +// string address uses a precalculated TypeSet hash, which are integers and +// typically are large and obviously not a list index +func indexesIntoTypeSet(key string) bool { + for _, part := range strings.Split(key, ".") { + if i, err := strconv.Atoi(part); err == nil && i > 100 { + return true + } + } + return false +} + +func checkIfIndexesIntoTypeSet(key string, f TestCheckFunc) TestCheckFunc { + return func(s *terraform.State) error { + err := f(s) + if err != nil && s.IsBinaryDrivenTest && indexesIntoTypeSet(key) { + return fmt.Errorf("Error in test check: %s\nTest check address %q likely indexes into TypeSet\nThis is currently not possible in the SDK", err, key) + } + return err + } +} + +func checkIfIndexesIntoTypeSetPair(keyFirst, keySecond string, f TestCheckFunc) TestCheckFunc { + return func(s *terraform.State) error { + err := f(s) + if err != nil && s.IsBinaryDrivenTest && (indexesIntoTypeSet(keyFirst) || indexesIntoTypeSet(keySecond)) { + return fmt.Errorf("Error in test check: %s\nTest check address %q or %q likely indexes into TypeSet\nThis is currently not possible in the SDK", err, keyFirst, keySecond) + } + return err + } +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_config.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_config.go new file mode 100644 index 00000000000..f56c885be32 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_config.go @@ -0,0 +1,28 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest" +) + +func testStepTaint(ctx context.Context, step TestStep, wd *plugintest.WorkingDir) error { + if len(step.Taint) == 0 { + return nil + } + + logging.HelperResourceTrace(ctx, fmt.Sprintf("Using TestStep Taint: %v", step.Taint)) + + for _, p := range step.Taint { + err := wd.Taint(ctx, p) + if err != nil { + return fmt.Errorf("error tainting resource: %s", err) + } + } + return nil +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new.go new file mode 100644 index 00000000000..14b247306af --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new.go @@ -0,0 +1,443 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp" + tfjson "github.com/hashicorp/terraform-json" + "github.com/mitchellh/go-testing-interface" + + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func runPostTestDestroy(ctx context.Context, t testing.T, c TestCase, wd *plugintest.WorkingDir, providers *providerFactories, statePreDestroy *terraform.State) error { + t.Helper() + + err := runProviderCommand(ctx, t, func() error { + return wd.Destroy(ctx) + }, wd, providers) + if err != nil { + return err + } + + if c.CheckDestroy != nil { + logging.HelperResourceTrace(ctx, "Using TestCase CheckDestroy") + logging.HelperResourceDebug(ctx, "Calling TestCase CheckDestroy") + + if err := c.CheckDestroy(statePreDestroy); err != nil { + return err + } + + logging.HelperResourceDebug(ctx, "Called TestCase CheckDestroy") + } + + return nil +} + +func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest.Helper) { + t.Helper() + + wd := helper.RequireNewWorkingDir(ctx, t) + + ctx = logging.TestTerraformPathContext(ctx, wd.GetHelper().TerraformExecPath()) + ctx = logging.TestWorkingDirectoryContext(ctx, wd.GetHelper().WorkingDirectory()) + + providers := &providerFactories{ + legacy: c.ProviderFactories, + protov5: c.ProtoV5ProviderFactories, + protov6: c.ProtoV6ProviderFactories, + } + + defer func() { + var statePreDestroy *terraform.State + var err error + err = runProviderCommand(ctx, t, func() error { + statePreDestroy, err = getState(ctx, t, wd) + if err != nil { + return err + } + return nil + }, wd, providers) + if err != nil { + logging.HelperResourceError(ctx, + "Error retrieving state, there may be dangling resources", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("Error retrieving state, there may be dangling resources: %s", err.Error()) + return + } + + if !stateIsEmpty(statePreDestroy) { + err := runPostTestDestroy(ctx, t, c, wd, providers, statePreDestroy) + if err != nil { + logging.HelperResourceError(ctx, + "Error running post-test destroy, there may be dangling resources", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("Error running post-test destroy, there may be dangling resources: %s", err.Error()) + } + } + + wd.Close() + }() + + if c.hasProviders(ctx) { + err := wd.SetConfig(ctx, c.providerConfig(ctx, false)) + + if err != nil { + logging.HelperResourceError(ctx, + "TestCase error setting provider configuration", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("TestCase error setting provider configuration: %s", err) + } + + err = runProviderCommand(ctx, t, func() error { + return wd.Init(ctx) + }, wd, providers) + + if err != nil { + logging.HelperResourceError(ctx, + "TestCase error running init", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("TestCase error running init: %s", err.Error()) + } + } + + logging.HelperResourceDebug(ctx, "Starting TestSteps") + + // use this to track last step successfully applied + // acts as default for import tests + var appliedCfg string + + for stepIndex, step := range c.Steps { + stepNumber := stepIndex + 1 // 1-based indexing for humans + ctx = logging.TestStepNumberContext(ctx, stepNumber) + + logging.HelperResourceDebug(ctx, "Starting TestStep") + + if step.PreConfig != nil { + logging.HelperResourceDebug(ctx, "Calling TestStep PreConfig") + step.PreConfig() + logging.HelperResourceDebug(ctx, "Called TestStep PreConfig") + } + + if step.SkipFunc != nil { + logging.HelperResourceDebug(ctx, "Calling TestStep SkipFunc") + + skip, err := step.SkipFunc() + if err != nil { + logging.HelperResourceError(ctx, + "Error calling TestStep SkipFunc", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("Error calling TestStep SkipFunc: %s", err.Error()) + } + + logging.HelperResourceDebug(ctx, "Called TestStep SkipFunc") + + if skip { + t.Logf("Skipping step %d/%d due to SkipFunc", stepNumber, len(c.Steps)) + logging.HelperResourceWarn(ctx, "Skipping TestStep due to SkipFunc") + continue + } + } + + if step.Config != "" && !step.Destroy && len(step.Taint) > 0 { + err := testStepTaint(ctx, step, wd) + + if err != nil { + logging.HelperResourceError(ctx, + "TestStep error tainting resources", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("TestStep %d/%d error tainting resources: %s", stepNumber, len(c.Steps), err) + } + } + + if step.hasProviders(ctx) { + providers = &providerFactories{ + legacy: sdkProviderFactories(c.ProviderFactories).merge(step.ProviderFactories), + protov5: protov5ProviderFactories(c.ProtoV5ProviderFactories).merge(step.ProtoV5ProviderFactories), + protov6: protov6ProviderFactories(c.ProtoV6ProviderFactories).merge(step.ProtoV6ProviderFactories), + } + + providerCfg := step.providerConfig(ctx, step.configHasProviderBlock(ctx)) + + err := wd.SetConfig(ctx, providerCfg) + + if err != nil { + logging.HelperResourceError(ctx, + "TestStep error setting provider configuration", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("TestStep %d/%d error setting test provider configuration: %s", stepNumber, len(c.Steps), err) + } + + err = runProviderCommand( + ctx, + t, + func() error { + return wd.Init(ctx) + }, + wd, + providers, + ) + + if err != nil { + logging.HelperResourceError(ctx, + "TestStep error running init", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("TestStep %d/%d running init: %s", stepNumber, len(c.Steps), err.Error()) + return + } + } + + if step.ImportState { + logging.HelperResourceTrace(ctx, "TestStep is ImportState mode") + + err := testStepNewImportState(ctx, t, helper, wd, step, appliedCfg, providers) + if step.ExpectError != nil { + logging.HelperResourceDebug(ctx, "Checking TestStep ExpectError") + if err == nil { + logging.HelperResourceError(ctx, + "Error running import: expected an error but got none", + ) + t.Fatalf("Step %d/%d error running import: expected an error but got none", stepNumber, len(c.Steps)) + } + if !step.ExpectError.MatchString(err.Error()) { + logging.HelperResourceError(ctx, + fmt.Sprintf("Error running import: expected an error with pattern (%s)", step.ExpectError.String()), + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("Step %d/%d error running import, expected an error with pattern (%s), no match on: %s", stepNumber, len(c.Steps), step.ExpectError.String(), err) + } + } else { + if err != nil && c.ErrorCheck != nil { + logging.HelperResourceDebug(ctx, "Calling TestCase ErrorCheck") + err = c.ErrorCheck(err) + logging.HelperResourceDebug(ctx, "Called TestCase ErrorCheck") + } + if err != nil { + logging.HelperResourceError(ctx, + "Error running import", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("Step %d/%d error running import: %s", stepNumber, len(c.Steps), err) + } + } + + logging.HelperResourceDebug(ctx, "Finished TestStep") + + continue + } + + if step.RefreshState { + logging.HelperResourceTrace(ctx, "TestStep is RefreshState mode") + + err := testStepNewRefreshState(ctx, t, wd, step, providers) + if step.ExpectError != nil { + logging.HelperResourceDebug(ctx, "Checking TestStep ExpectError") + if err == nil { + logging.HelperResourceError(ctx, + "Error running refresh: expected an error but got none", + ) + t.Fatalf("Step %d/%d error running refresh: expected an error but got none", stepNumber, len(c.Steps)) + } + if !step.ExpectError.MatchString(err.Error()) { + logging.HelperResourceError(ctx, + fmt.Sprintf("Error running refresh: expected an error with pattern (%s)", step.ExpectError.String()), + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("Step %d/%d error running refresh, expected an error with pattern (%s), no match on: %s", stepNumber, len(c.Steps), step.ExpectError.String(), err) + } + } else { + if err != nil && c.ErrorCheck != nil { + logging.HelperResourceDebug(ctx, "Calling TestCase ErrorCheck") + err = c.ErrorCheck(err) + logging.HelperResourceDebug(ctx, "Called TestCase ErrorCheck") + } + if err != nil { + logging.HelperResourceError(ctx, + "Error running refresh", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("Step %d/%d error running refresh: %s", stepNumber, len(c.Steps), err) + } + } + + logging.HelperResourceDebug(ctx, "Finished TestStep") + + continue + } + + if step.Config != "" { + logging.HelperResourceTrace(ctx, "TestStep is Config mode") + + err := testStepNewConfig(ctx, t, c, wd, step, providers) + if step.ExpectError != nil { + logging.HelperResourceDebug(ctx, "Checking TestStep ExpectError") + + if err == nil { + logging.HelperResourceError(ctx, + "Expected an error but got none", + ) + t.Fatalf("Step %d/%d, expected an error but got none", stepNumber, len(c.Steps)) + } + if !step.ExpectError.MatchString(err.Error()) { + logging.HelperResourceError(ctx, + fmt.Sprintf("Expected an error with pattern (%s)", step.ExpectError.String()), + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("Step %d/%d, expected an error with pattern, no match on: %s", stepNumber, len(c.Steps), err) + } + } else { + if err != nil && c.ErrorCheck != nil { + logging.HelperResourceDebug(ctx, "Calling TestCase ErrorCheck") + + err = c.ErrorCheck(err) + + logging.HelperResourceDebug(ctx, "Called TestCase ErrorCheck") + } + if err != nil { + logging.HelperResourceError(ctx, + "Unexpected error", + map[string]interface{}{logging.KeyError: err}, + ) + t.Fatalf("Step %d/%d error: %s", stepNumber, len(c.Steps), err) + } + } + + appliedCfg = step.mergedConfig(ctx, c) + + logging.HelperResourceDebug(ctx, "Finished TestStep") + + continue + } + + t.Fatalf("Step %d/%d, unsupported test mode", stepNumber, len(c.Steps)) + } +} + +func getState(ctx context.Context, t testing.T, wd *plugintest.WorkingDir) (*terraform.State, error) { + t.Helper() + + jsonState, err := wd.State(ctx) + if err != nil { + return nil, err + } + state, err := shimStateFromJson(jsonState) + if err != nil { + t.Fatal(err) + } + return state, nil +} + +func stateIsEmpty(state *terraform.State) bool { + return state.Empty() || !state.HasResources() +} + +func planIsEmpty(plan *tfjson.Plan) bool { + for _, rc := range plan.ResourceChanges { + for _, a := range rc.Change.Actions { + if a != tfjson.ActionNoop { + return false + } + } + } + return true +} + +func testIDRefresh(ctx context.Context, t testing.T, c TestCase, wd *plugintest.WorkingDir, step TestStep, r *terraform.ResourceState, providers *providerFactories) error { + t.Helper() + + // Build the state. The state is just the resource with an ID. There + // are no attributes. We only set what is needed to perform a refresh. + state := terraform.NewState() + state.RootModule().Resources = make(map[string]*terraform.ResourceState) + state.RootModule().Resources[c.IDRefreshName] = &terraform.ResourceState{} + + // Temporarily set the config to a minimal provider config for the refresh + // test. After the refresh we can reset it. + err := wd.SetConfig(ctx, c.providerConfig(ctx, step.configHasProviderBlock(ctx))) + if err != nil { + t.Fatalf("Error setting import test config: %s", err) + } + defer func() { + err = wd.SetConfig(ctx, step.Config) + if err != nil { + t.Fatalf("Error resetting test config: %s", err) + } + }() + + // Refresh! + err = runProviderCommand(ctx, t, func() error { + err = wd.Refresh(ctx) + if err != nil { + t.Fatalf("Error running terraform refresh: %s", err) + } + state, err = getState(ctx, t, wd) + if err != nil { + return err + } + return nil + }, wd, providers) + if err != nil { + return err + } + + // Verify attribute equivalence. + actualR := state.RootModule().Resources[c.IDRefreshName] + if actualR == nil { + return fmt.Errorf("Resource gone!") + } + if actualR.Primary == nil { + return fmt.Errorf("Resource has no primary instance") + } + actual := actualR.Primary.Attributes + expected := r.Primary.Attributes + + if len(c.IDRefreshIgnore) > 0 { + logging.HelperResourceTrace(ctx, fmt.Sprintf("Using TestCase IDRefreshIgnore: %v", c.IDRefreshIgnore)) + } + + // Remove fields we're ignoring + for _, v := range c.IDRefreshIgnore { + for k := range actual { + if strings.HasPrefix(k, v) { + delete(actual, k) + } + } + for k := range expected { + if strings.HasPrefix(k, v) { + delete(expected, k) + } + } + } + + if !reflect.DeepEqual(actual, expected) { + // Determine only the different attributes + for k, v := range expected { + if av, ok := actual[k]; ok && v == av { + delete(expected, k) + delete(actual, k) + } + } + + if diff := cmp.Diff(expected, actual); diff != "" { + return fmt.Errorf("IDRefreshName attributes not equivalent. Difference is shown below. The - symbol indicates attributes missing after refresh.\n\n%s", diff) + } + } + + return nil +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_config.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_config.go new file mode 100644 index 00000000000..a52008768fb --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_config.go @@ -0,0 +1,244 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "errors" + "fmt" + + tfjson "github.com/hashicorp/terraform-json" + testing "github.com/mitchellh/go-testing-interface" + + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func testStepNewConfig(ctx context.Context, t testing.T, c TestCase, wd *plugintest.WorkingDir, step TestStep, providers *providerFactories) error { + t.Helper() + + err := wd.SetConfig(ctx, step.mergedConfig(ctx, c)) + if err != nil { + return fmt.Errorf("Error setting config: %w", err) + } + + // require a refresh before applying + // failing to do this will result in data sources not being updated + err = runProviderCommand(ctx, t, func() error { + return wd.Refresh(ctx) + }, wd, providers) + if err != nil { + return fmt.Errorf("Error running pre-apply refresh: %w", err) + } + + // If this step is a PlanOnly step, skip over this first Plan and + // subsequent Apply, and use the follow-up Plan that checks for + // permadiffs + if !step.PlanOnly { + logging.HelperResourceDebug(ctx, "Running Terraform CLI plan and apply") + + // Plan! + err := runProviderCommand(ctx, t, func() error { + if step.Destroy { + return wd.CreateDestroyPlan(ctx) + } + return wd.CreatePlan(ctx) + }, wd, providers) + if err != nil { + return fmt.Errorf("Error running pre-apply plan: %w", err) + } + + // We need to keep a copy of the state prior to destroying such + // that the destroy steps can verify their behavior in the + // check function + var stateBeforeApplication *terraform.State + err = runProviderCommand(ctx, t, func() error { + stateBeforeApplication, err = getState(ctx, t, wd) + if err != nil { + return err + } + return nil + }, wd, providers) + if err != nil { + return fmt.Errorf("Error retrieving pre-apply state: %w", err) + } + + // Apply the diff, creating real resources + err = runProviderCommand(ctx, t, func() error { + return wd.Apply(ctx) + }, wd, providers) + if err != nil { + if step.Destroy { + return fmt.Errorf("Error running destroy: %w", err) + } + return fmt.Errorf("Error running apply: %w", err) + } + + // Get the new state + var state *terraform.State + err = runProviderCommand(ctx, t, func() error { + state, err = getState(ctx, t, wd) + if err != nil { + return err + } + return nil + }, wd, providers) + if err != nil { + return fmt.Errorf("Error retrieving state after apply: %w", err) + } + + // Run any configured checks + if step.Check != nil { + logging.HelperResourceTrace(ctx, "Using TestStep Check") + + state.IsBinaryDrivenTest = true + if step.Destroy { + if err := step.Check(stateBeforeApplication); err != nil { + return fmt.Errorf("Check failed: %w", err) + } + } else { + if err := step.Check(state); err != nil { + return fmt.Errorf("Check failed: %w", err) + } + } + } + } + + // Test for perpetual diffs by performing a plan, a refresh, and another plan + logging.HelperResourceDebug(ctx, "Running Terraform CLI plan to check for perpetual differences") + + // do a plan + err = runProviderCommand(ctx, t, func() error { + if step.Destroy { + return wd.CreateDestroyPlan(ctx) + } + return wd.CreatePlan(ctx) + }, wd, providers) + if err != nil { + return fmt.Errorf("Error running post-apply plan: %w", err) + } + + var plan *tfjson.Plan + err = runProviderCommand(ctx, t, func() error { + var err error + plan, err = wd.SavedPlan(ctx) + return err + }, wd, providers) + if err != nil { + return fmt.Errorf("Error retrieving post-apply plan: %w", err) + } + + if !planIsEmpty(plan) && !step.ExpectNonEmptyPlan { + var stdout string + err = runProviderCommand(ctx, t, func() error { + var err error + stdout, err = wd.SavedPlanRawStdout(ctx) + return err + }, wd, providers) + if err != nil { + return fmt.Errorf("Error retrieving formatted plan output: %w", err) + } + return fmt.Errorf("After applying this test step, the plan was not empty.\nstdout:\n\n%s", stdout) + } + + // do a refresh + if !step.Destroy || (step.Destroy && !step.PreventPostDestroyRefresh) { + err := runProviderCommand(ctx, t, func() error { + return wd.Refresh(ctx) + }, wd, providers) + if err != nil { + return fmt.Errorf("Error running post-apply refresh: %w", err) + } + } + + // do another plan + err = runProviderCommand(ctx, t, func() error { + if step.Destroy { + return wd.CreateDestroyPlan(ctx) + } + return wd.CreatePlan(ctx) + }, wd, providers) + if err != nil { + return fmt.Errorf("Error running second post-apply plan: %w", err) + } + + err = runProviderCommand(ctx, t, func() error { + var err error + plan, err = wd.SavedPlan(ctx) + return err + }, wd, providers) + if err != nil { + return fmt.Errorf("Error retrieving second post-apply plan: %w", err) + } + + // check if plan is empty + if !planIsEmpty(plan) && !step.ExpectNonEmptyPlan { + var stdout string + err = runProviderCommand(ctx, t, func() error { + var err error + stdout, err = wd.SavedPlanRawStdout(ctx) + return err + }, wd, providers) + if err != nil { + return fmt.Errorf("Error retrieving formatted second plan output: %w", err) + } + return fmt.Errorf("After applying this test step and performing a `terraform refresh`, the plan was not empty.\nstdout\n\n%s", stdout) + } else if step.ExpectNonEmptyPlan && planIsEmpty(plan) { + return errors.New("Expected a non-empty plan, but got an empty plan") + } + + // ID-ONLY REFRESH + // If we've never checked an id-only refresh and our state isn't + // empty, find the first resource and test it. + if c.IDRefreshName != "" { + logging.HelperResourceTrace(ctx, "Using TestCase IDRefreshName") + + var state *terraform.State + + err = runProviderCommand(ctx, t, func() error { + state, err = getState(ctx, t, wd) + if err != nil { + return err + } + return nil + }, wd, providers) + + if err != nil { + return err + } + + if state.Empty() { + return nil + } + + var idRefreshCheck *terraform.ResourceState + + // Find the first non-nil resource in the state + for _, m := range state.Modules { + if len(m.Resources) > 0 { + if v, ok := m.Resources[c.IDRefreshName]; ok { + idRefreshCheck = v + } + + break + } + } + + // If we have an instance to check for refreshes, do it + // immediately. We do it in the middle of another test + // because it shouldn't affect the overall state (refresh + // is read-only semantically) and we want to fail early if + // this fails. If refresh isn't read-only, then this will have + // caught a different bug. + if idRefreshCheck != nil { + if err := testIDRefresh(ctx, t, c, wd, step, idRefreshCheck, providers); err != nil { + return fmt.Errorf( + "[ERROR] Test: ID-only test failed: %s", err) + } + } + } + + return nil +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_import_state.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_import_state.go new file mode 100644 index 00000000000..4ddf56c5b28 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_import_state.go @@ -0,0 +1,281 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp" + "github.com/mitchellh/go-testing-interface" + + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest.Helper, wd *plugintest.WorkingDir, step TestStep, cfg string, providers *providerFactories) error { + t.Helper() + + if step.ResourceName == "" { + t.Fatal("ResourceName is required for an import state test") + } + + // get state from check sequence + var state *terraform.State + var err error + err = runProviderCommand(ctx, t, func() error { + state, err = getState(ctx, t, wd) + if err != nil { + return err + } + return nil + }, wd, providers) + if err != nil { + t.Fatalf("Error getting state: %s", err) + } + + // Determine the ID to import + var importId string + switch { + case step.ImportStateIdFunc != nil: + logging.HelperResourceTrace(ctx, "Using TestStep ImportStateIdFunc for import identifier") + + var err error + + logging.HelperResourceDebug(ctx, "Calling TestStep ImportStateIdFunc") + + importId, err = step.ImportStateIdFunc(state) + + if err != nil { + t.Fatal(err) + } + + logging.HelperResourceDebug(ctx, "Called TestStep ImportStateIdFunc") + case step.ImportStateId != "": + logging.HelperResourceTrace(ctx, "Using TestStep ImportStateId for import identifier") + + importId = step.ImportStateId + default: + logging.HelperResourceTrace(ctx, "Using resource identifier for import identifier") + + resource, err := testResource(step, state) + if err != nil { + t.Fatal(err) + } + importId = resource.Primary.ID + } + + if step.ImportStateIdPrefix != "" { + logging.HelperResourceTrace(ctx, "Prepending TestStep ImportStateIdPrefix for import identifier") + + importId = step.ImportStateIdPrefix + importId + } + + logging.HelperResourceTrace(ctx, fmt.Sprintf("Using import identifier: %s", importId)) + + // Create working directory for import tests + if step.Config == "" { + logging.HelperResourceTrace(ctx, "Using prior TestStep Config for import") + + step.Config = cfg + if step.Config == "" { + t.Fatal("Cannot import state with no specified config") + } + } + + var importWd *plugintest.WorkingDir + + // Use the same working directory to persist the state from import + if step.ImportStatePersist { + importWd = wd + } else { + importWd = helper.RequireNewWorkingDir(ctx, t) + defer importWd.Close() + } + + err = importWd.SetConfig(ctx, step.Config) + if err != nil { + t.Fatalf("Error setting test config: %s", err) + } + + logging.HelperResourceDebug(ctx, "Running Terraform CLI init and import") + + if !step.ImportStatePersist { + err = runProviderCommand(ctx, t, func() error { + return importWd.Init(ctx) + }, importWd, providers) + if err != nil { + t.Fatalf("Error running init: %s", err) + } + } + + err = runProviderCommand(ctx, t, func() error { + return importWd.Import(ctx, step.ResourceName, importId) + }, importWd, providers) + if err != nil { + return err + } + + var importState *terraform.State + err = runProviderCommand(ctx, t, func() error { + importState, err = getState(ctx, t, importWd) + if err != nil { + return err + } + return nil + }, importWd, providers) + if err != nil { + t.Fatalf("Error getting state: %s", err) + } + + // Go through the imported state and verify + if step.ImportStateCheck != nil { + logging.HelperResourceTrace(ctx, "Using TestStep ImportStateCheck") + + var states []*terraform.InstanceState + for address, r := range importState.RootModule().Resources { + if strings.HasPrefix(address, "data.") { + continue + } + + if r.Primary == nil { + continue + } + + is := r.Primary.DeepCopy() + is.Ephemeral.Type = r.Type // otherwise the check function cannot see the type + states = append(states, is) + } + + logging.HelperResourceDebug(ctx, "Calling TestStep ImportStateCheck") + + if err := step.ImportStateCheck(states); err != nil { + t.Fatal(err) + } + + logging.HelperResourceDebug(ctx, "Called TestStep ImportStateCheck") + } + + // Verify that all the states match + if step.ImportStateVerify { + logging.HelperResourceTrace(ctx, "Using TestStep ImportStateVerify") + + // Ensure that we do not match against data sources as they + // cannot be imported and are not what we want to verify. + // Mode is not present in ResourceState so we use the + // stringified ResourceStateKey for comparison. + newResources := make(map[string]*terraform.ResourceState) + for k, v := range importState.RootModule().Resources { + if !strings.HasPrefix(k, "data.") { + newResources[k] = v + } + } + oldResources := make(map[string]*terraform.ResourceState) + for k, v := range state.RootModule().Resources { + if !strings.HasPrefix(k, "data.") { + oldResources[k] = v + } + } + + for _, r := range newResources { + // Find the existing resource + var oldR *terraform.ResourceState + for _, r2 := range oldResources { + + if r2.Primary != nil && r2.Primary.ID == r.Primary.ID && r2.Type == r.Type && r2.Provider == r.Provider { + oldR = r2 + break + } + } + if oldR == nil || oldR.Primary == nil { + t.Fatalf( + "Failed state verification, resource with ID %s not found", + r.Primary.ID) + } + + // don't add empty flatmapped containers, so we can more easily + // compare the attributes + skipEmpty := func(k, v string) bool { + if strings.HasSuffix(k, ".#") || strings.HasSuffix(k, ".%") { + if v == "0" { + return true + } + } + return false + } + + // Compare their attributes + actual := make(map[string]string) + for k, v := range r.Primary.Attributes { + if skipEmpty(k, v) { + continue + } + actual[k] = v + } + + expected := make(map[string]string) + for k, v := range oldR.Primary.Attributes { + if skipEmpty(k, v) { + continue + } + expected[k] = v + } + + // Remove fields we're ignoring + for _, v := range step.ImportStateVerifyIgnore { + for k := range actual { + if strings.HasPrefix(k, v) { + delete(actual, k) + } + } + for k := range expected { + if strings.HasPrefix(k, v) { + delete(expected, k) + } + } + } + + // timeouts are only _sometimes_ added to state. To + // account for this, just don't compare timeouts at + // all. + for k := range actual { + if strings.HasPrefix(k, "timeouts.") { + delete(actual, k) + } + if k == "timeouts" { + delete(actual, k) + } + } + for k := range expected { + if strings.HasPrefix(k, "timeouts.") { + delete(expected, k) + } + if k == "timeouts" { + delete(expected, k) + } + } + + if !reflect.DeepEqual(actual, expected) { + // Determine only the different attributes + // go-cmp tries to show surrounding identical map key/value for + // context of differences, which may be confusing. + for k, v := range expected { + if av, ok := actual[k]; ok && v == av { + delete(expected, k) + delete(actual, k) + } + } + + if diff := cmp.Diff(expected, actual); diff != "" { + return fmt.Errorf("ImportStateVerify attributes not equivalent. Difference is shown below. The - symbol indicates attributes missing after import.\n\n%s", diff) + } + } + } + } + + return nil +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_refresh_state.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_refresh_state.go new file mode 100644 index 00000000000..627190a9d19 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_new_refresh_state.go @@ -0,0 +1,96 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "fmt" + + tfjson "github.com/hashicorp/terraform-json" + "github.com/mitchellh/go-testing-interface" + + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func testStepNewRefreshState(ctx context.Context, t testing.T, wd *plugintest.WorkingDir, step TestStep, providers *providerFactories) error { + t.Helper() + + var err error + // Explicitly ensure prior state exists before refresh. + err = runProviderCommand(ctx, t, func() error { + _, err = getState(ctx, t, wd) + if err != nil { + return err + } + return nil + }, wd, providers) + if err != nil { + t.Fatalf("Error getting state: %s", err) + } + + err = runProviderCommand(ctx, t, func() error { + return wd.Refresh(ctx) + }, wd, providers) + if err != nil { + return err + } + + var refreshState *terraform.State + err = runProviderCommand(ctx, t, func() error { + refreshState, err = getState(ctx, t, wd) + if err != nil { + return err + } + return nil + }, wd, providers) + if err != nil { + t.Fatalf("Error getting state: %s", err) + } + + // Go through the refreshed state and verify + if step.Check != nil { + logging.HelperResourceDebug(ctx, "Calling TestStep Check for RefreshState") + + if err := step.Check(refreshState); err != nil { + t.Fatal(err) + } + + logging.HelperResourceDebug(ctx, "Called TestStep Check for RefreshState") + } + + // do a plan + err = runProviderCommand(ctx, t, func() error { + return wd.CreatePlan(ctx) + }, wd, providers) + if err != nil { + return fmt.Errorf("Error running post-apply plan: %w", err) + } + + var plan *tfjson.Plan + err = runProviderCommand(ctx, t, func() error { + var err error + plan, err = wd.SavedPlan(ctx) + return err + }, wd, providers) + if err != nil { + return fmt.Errorf("Error retrieving post-apply plan: %w", err) + } + + if !planIsEmpty(plan) && !step.ExpectNonEmptyPlan { + var stdout string + err = runProviderCommand(ctx, t, func() error { + var err error + stdout, err = wd.SavedPlanRawStdout(ctx) + return err + }, wd, providers) + if err != nil { + return fmt.Errorf("Error retrieving formatted plan output: %w", err) + } + return fmt.Errorf("After refreshing state during this test step, a followup plan was not empty.\nstdout:\n\n%s", stdout) + } + + return nil +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_sets.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_sets.go new file mode 100644 index 00000000000..45cce957327 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/testing_sets.go @@ -0,0 +1,361 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// These test helpers were developed by the AWS provider team at HashiCorp. + +package resource + +import ( + "fmt" + "regexp" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +const ( + sentinelIndex = "*" +) + +// TestCheckTypeSetElemNestedAttrs ensures a subset map of values is stored in +// state for the given name and key combination of attributes nested under a +// list or set block. Use this TestCheckFunc in preference over non-set +// variants to simplify testing code and ensure compatibility with indices, +// which can easily change with schema changes. State value checking is only +// recommended for testing Computed attributes and attribute defaults. +// +// For managed resources, the name parameter is a combination of the resource +// type, a period (.), and the name label. The name for the below example +// configuration would be "myprovider_thing.example". +// +// resource "myprovider_thing" "example" { ... } +// +// For data sources, the name parameter is a combination of the keyword "data", +// a period (.), the data source type, a period (.), and the name label. The +// name for the below example configuration would be +// "data.myprovider_thing.example". +// +// data "myprovider_thing" "example" { ... } +// +// The key parameter is an attribute path in Terraform CLI 0.11 and earlier +// "flatmap" syntax. Keys start with the attribute name of a top-level +// attribute. Use the sentinel value '*' to replace the element indexing into +// a list or set. The sentinel value can be used for each list or set index, if +// there are multiple lists or sets in the attribute path. +// +// The values parameter is the map of attribute names to attribute values +// expected to be nested under the list or set. +// +// You may check for unset nested attributes, however this will also match keys +// set to an empty string. Use a map with at least 1 non-empty value. +// +// map[string]string{ +// "key1": "value", +// "key2": "", +// } +// +// If the values map is not granular enough, it is possible to match an element +// you were not intending to in the set. Provide the most complete mapping of +// attributes possible to be sure the unique element exists. +func TestCheckTypeSetElemNestedAttrs(name, attr string, values map[string]string) TestCheckFunc { + return func(s *terraform.State) error { + is, err := primaryInstanceState(s, name) + if err != nil { + return err + } + + attrParts := strings.Split(attr, ".") + if attrParts[len(attrParts)-1] != sentinelIndex { + return fmt.Errorf("%q does not end with the special value %q", attr, sentinelIndex) + } + // account for cases where the user is trying to see if the value is unset/empty + // there may be ambiguous scenarios where a field was deliberately unset vs set + // to the empty string, this will match both, which may be a false positive. + var matchCount int + for _, v := range values { + if v != "" { + matchCount++ + } + } + if matchCount == 0 { + return fmt.Errorf("%#v has no non-empty values", values) + } + + if testCheckTypeSetElemNestedAttrsInState(is, attrParts, matchCount, values) { + return nil + } + return fmt.Errorf("%q no TypeSet element %q, with nested attrs %#v in state: %#v", name, attr, values, is.Attributes) + } +} + +// TestMatchTypeSetElemNestedAttrs ensures a subset map of values, compared by +// regular expressions, is stored in state for the given name and key +// combination of attributes nested under a list or set block. Use this +// TestCheckFunc in preference over non-set variants to simplify testing code +// and ensure compatibility with indices, which can easily change with schema +// changes. State value checking is only recommended for testing Computed +// attributes and attribute defaults. +// +// For managed resources, the name parameter is a combination of the resource +// type, a period (.), and the name label. The name for the below example +// configuration would be "myprovider_thing.example". +// +// resource "myprovider_thing" "example" { ... } +// +// For data sources, the name parameter is a combination of the keyword "data", +// a period (.), the data source type, a period (.), and the name label. The +// name for the below example configuration would be +// "data.myprovider_thing.example". +// +// data "myprovider_thing" "example" { ... } +// +// The key parameter is an attribute path in Terraform CLI 0.11 and earlier +// "flatmap" syntax. Keys start with the attribute name of a top-level +// attribute. Use the sentinel value '*' to replace the element indexing into +// a list or set. The sentinel value can be used for each list or set index, if +// there are multiple lists or sets in the attribute path. +// +// The values parameter is the map of attribute names to regular expressions +// for matching attribute values expected to be nested under the list or set. +// +// You may check for unset nested attributes, however this will also match keys +// set to an empty string. Use a map with at least 1 non-empty value. +// +// map[string]*regexp.Regexp{ +// "key1": regexp.MustCompile(`^value`), +// "key2": regexp.MustCompile(`^$`), +// } +// +// If the values map is not granular enough, it is possible to match an element +// you were not intending to in the set. Provide the most complete mapping of +// attributes possible to be sure the unique element exists. +func TestMatchTypeSetElemNestedAttrs(name, attr string, values map[string]*regexp.Regexp) TestCheckFunc { + return func(s *terraform.State) error { + is, err := primaryInstanceState(s, name) + if err != nil { + return err + } + + attrParts := strings.Split(attr, ".") + if attrParts[len(attrParts)-1] != sentinelIndex { + return fmt.Errorf("%q does not end with the special value %q", attr, sentinelIndex) + } + // account for cases where the user is trying to see if the value is unset/empty + // there may be ambiguous scenarios where a field was deliberately unset vs set + // to the empty string, this will match both, which may be a false positive. + var matchCount int + for _, v := range values { + if v != nil { + matchCount++ + } + } + if matchCount == 0 { + return fmt.Errorf("%#v has no non-empty values", values) + } + + if testCheckTypeSetElemNestedAttrsInState(is, attrParts, matchCount, values) { + return nil + } + return fmt.Errorf("%q no TypeSet element %q, with the regex provided, match in state: %#v", name, attr, is.Attributes) + } +} + +// TestCheckTypeSetElemAttr is a TestCheckFunc that accepts a resource +// name, an attribute path, which should use the sentinel value '*' for indexing +// into a TypeSet. The function verifies that an element matches the provided +// value. +// +// Use this function over SDK provided TestCheckFunctions when validating a +// TypeSet where its elements are a simple value + +// TestCheckTypeSetElemAttr ensures a specific value is stored in state for the +// given name and key combination under a list or set. Use this TestCheckFunc +// in preference over non-set variants to simplify testing code and ensure +// compatibility with indices, which can easily change with schema changes. +// State value checking is only recommended for testing Computed attributes and +// attribute defaults. +// +// For managed resources, the name parameter is a combination of the resource +// type, a period (.), and the name label. The name for the below example +// configuration would be "myprovider_thing.example". +// +// resource "myprovider_thing" "example" { ... } +// +// For data sources, the name parameter is a combination of the keyword "data", +// a period (.), the data source type, a period (.), and the name label. The +// name for the below example configuration would be +// "data.myprovider_thing.example". +// +// data "myprovider_thing" "example" { ... } +// +// The key parameter is an attribute path in Terraform CLI 0.11 and earlier +// "flatmap" syntax. Keys start with the attribute name of a top-level +// attribute. Use the sentinel value '*' to replace the element indexing into +// a list or set. The sentinel value can be used for each list or set index, if +// there are multiple lists or sets in the attribute path. +// +// The value parameter is the stringified data to check at the given key. Use +// the following attribute type rules to set the value: +// +// - Boolean: "false" or "true". +// - Float/Integer: Stringified number, such as "1.2" or "123". +// - String: No conversion necessary. +func TestCheckTypeSetElemAttr(name, attr, value string) TestCheckFunc { + return func(s *terraform.State) error { + is, err := primaryInstanceState(s, name) + if err != nil { + return err + } + + err = testCheckTypeSetElem(is, attr, value) + if err != nil { + return fmt.Errorf("%q error: %s", name, err) + } + + return nil + } +} + +// TestCheckTypeSetElemAttrPair ensures value equality in state between the +// first given name and key combination and the second name and key +// combination. State value checking is only recommended for testing Computed +// attributes and attribute defaults. +// +// For managed resources, the name parameter is a combination of the resource +// type, a period (.), and the name label. The name for the below example +// configuration would be "myprovider_thing.example". +// +// resource "myprovider_thing" "example" { ... } +// +// For data sources, the name parameter is a combination of the keyword "data", +// a period (.), the data source type, a period (.), and the name label. The +// name for the below example configuration would be +// "data.myprovider_thing.example". +// +// data "myprovider_thing" "example" { ... } +// +// The first and second names may use any combination of managed resources +// and/or data sources. +// +// The key parameter is an attribute path in Terraform CLI 0.11 and earlier +// "flatmap" syntax. Keys start with the attribute name of a top-level +// attribute. Use the sentinel value '*' to replace the element indexing into +// a list or set. The sentinel value can be used for each list or set index, if +// there are multiple lists or sets in the attribute path. +func TestCheckTypeSetElemAttrPair(nameFirst, keyFirst, nameSecond, keySecond string) TestCheckFunc { + return func(s *terraform.State) error { + isFirst, err := primaryInstanceState(s, nameFirst) + if err != nil { + return err + } + + isSecond, err := primaryInstanceState(s, nameSecond) + if err != nil { + return err + } + + vSecond, okSecond := isSecond.Attributes[keySecond] + if !okSecond { + return fmt.Errorf("%s: Attribute %q not set, cannot be checked against TypeSet", nameSecond, keySecond) + } + + return testCheckTypeSetElemPair(isFirst, keyFirst, vSecond) + } +} + +func testCheckTypeSetElem(is *terraform.InstanceState, attr, value string) error { + attrParts := strings.Split(attr, ".") + if attrParts[len(attrParts)-1] != sentinelIndex { + return fmt.Errorf("%q does not end with the special value %q", attr, sentinelIndex) + } + for stateKey, stateValue := range is.Attributes { + if stateValue == value { + stateKeyParts := strings.Split(stateKey, ".") + if len(stateKeyParts) == len(attrParts) { + for i := range attrParts { + if attrParts[i] != stateKeyParts[i] && attrParts[i] != sentinelIndex { + break + } + if i == len(attrParts)-1 { + return nil + } + } + } + } + } + + return fmt.Errorf("no TypeSet element %q, with value %q in state: %#v", attr, value, is.Attributes) +} + +func testCheckTypeSetElemPair(is *terraform.InstanceState, attr, value string) error { + attrParts := strings.Split(attr, ".") + for stateKey, stateValue := range is.Attributes { + if stateValue == value { + stateKeyParts := strings.Split(stateKey, ".") + if len(stateKeyParts) == len(attrParts) { + for i := range attrParts { + if attrParts[i] != stateKeyParts[i] && attrParts[i] != sentinelIndex { + break + } + if i == len(attrParts)-1 { + return nil + } + } + } + } + } + + return fmt.Errorf("no TypeSet element %q, with value %q in state: %#v", attr, value, is.Attributes) +} + +// testCheckTypeSetElemNestedAttrsInState is a helper function +// to determine if nested attributes and their values are equal to those +// in the instance state. Currently, the function accepts a "values" param of type +// map[string]string or map[string]*regexp.Regexp. +// Returns true if all attributes match, else false. +func testCheckTypeSetElemNestedAttrsInState(is *terraform.InstanceState, attrParts []string, matchCount int, values interface{}) bool { + matches := make(map[string]int) + + for stateKey, stateValue := range is.Attributes { + stateKeyParts := strings.Split(stateKey, ".") + // a Set/List item with nested attrs would have a flatmap address of + // at least length 3 + // foo.0.name = "bar" + if len(stateKeyParts) < 3 || len(attrParts) > len(stateKeyParts) { + continue + } + var pathMatch bool + for i := range attrParts { + if attrParts[i] != stateKeyParts[i] && attrParts[i] != sentinelIndex { + break + } + if i == len(attrParts)-1 { + pathMatch = true + } + } + if !pathMatch { + continue + } + id := stateKeyParts[len(attrParts)-1] + nestedAttr := strings.Join(stateKeyParts[len(attrParts):], ".") + + var match bool + switch t := values.(type) { + case map[string]string: + if v, keyExists := t[nestedAttr]; keyExists && v == stateValue { + match = true + } + case map[string]*regexp.Regexp: + if v, keyExists := t[nestedAttr]; keyExists && v != nil && v.MatchString(stateValue) { + match = true + } + } + if match { + matches[id] = matches[id] + 1 + if matches[id] == matchCount { + return true + } + } + } + return false +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/teststep_providers.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/teststep_providers.go new file mode 100644 index 00000000000..9b759bde03a --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/teststep_providers.go @@ -0,0 +1,97 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "fmt" + "regexp" + "strings" +) + +var configProviderBlockRegex = regexp.MustCompile(`provider "?[a-zA-Z0-9_-]+"? {`) + +// configHasProviderBlock returns true if the Config has declared a provider +// configuration block, e.g. provider "examplecloud" {...} +func (s TestStep) configHasProviderBlock(_ context.Context) bool { + return configProviderBlockRegex.MatchString(s.Config) +} + +// configHasTerraformBlock returns true if the Config has declared a terraform +// configuration block, e.g. terraform {...} +func (s TestStep) configHasTerraformBlock(_ context.Context) bool { + return strings.Contains(s.Config, "terraform {") +} + +// mergedConfig prepends any necessary terraform configuration blocks to the +// TestStep Config. +// +// If there are ExternalProviders configurations in either the TestCase or +// TestStep, the terraform configuration block should be included with the +// step configuration to prevent errors with providers outside the +// registry.terraform.io hostname or outside the hashicorp namespace. +func (s TestStep) mergedConfig(ctx context.Context, testCase TestCase) string { + var config strings.Builder + + // Prevent issues with existing configurations containing the terraform + // configuration block. + if s.configHasTerraformBlock(ctx) { + config.WriteString(s.Config) + + return config.String() + } + + if testCase.hasProviders(ctx) { + config.WriteString(testCase.providerConfig(ctx, s.configHasProviderBlock(ctx))) + } else { + config.WriteString(s.providerConfig(ctx, s.configHasProviderBlock(ctx))) + } + + config.WriteString(s.Config) + + return config.String() +} + +// providerConfig takes the list of providers in a TestStep and returns a +// config with only empty provider blocks. This is useful for Import, where no +// config is provided, but the providers must be defined. +func (s TestStep) providerConfig(_ context.Context, skipProviderBlock bool) string { + var providerBlocks, requiredProviderBlocks strings.Builder + + for name, externalProvider := range s.ExternalProviders { + if !skipProviderBlock { + providerBlocks.WriteString(fmt.Sprintf("provider %q {}\n", name)) + } + + if externalProvider.Source == "" && externalProvider.VersionConstraint == "" { + continue + } + + requiredProviderBlocks.WriteString(fmt.Sprintf(" %s = {\n", name)) + + if externalProvider.Source != "" { + requiredProviderBlocks.WriteString(fmt.Sprintf(" source = %q\n", externalProvider.Source)) + } + + if externalProvider.VersionConstraint != "" { + requiredProviderBlocks.WriteString(fmt.Sprintf(" version = %q\n", externalProvider.VersionConstraint)) + } + + requiredProviderBlocks.WriteString(" }\n") + } + + if requiredProviderBlocks.Len() > 0 { + return fmt.Sprintf(` +terraform { + required_providers { +%[1]s + } +} + +%[2]s +`, strings.TrimSuffix(requiredProviderBlocks.String(), "\n"), providerBlocks.String()) + } + + return providerBlocks.String() +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/teststep_validate.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/teststep_validate.go new file mode 100644 index 00000000000..7dbf883b504 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource/teststep_validate.go @@ -0,0 +1,128 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resource + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" +) + +// testStepValidateRequest contains data for the (TestStep).validate() method. +type testStepValidateRequest struct { + // StepNumber is the index of the TestStep in the TestCase.Steps. + StepNumber int + + // TestCaseHasProviders is enabled if the TestCase has set any of + // ExternalProviders, ProtoV5ProviderFactories, ProtoV6ProviderFactories, + // or ProviderFactories. + TestCaseHasProviders bool +} + +// hasProviders returns true if the TestStep has set any of the +// ExternalProviders, ProtoV5ProviderFactories, ProtoV6ProviderFactories, or +// ProviderFactories fields. +func (s TestStep) hasProviders(_ context.Context) bool { + if len(s.ExternalProviders) > 0 { + return true + } + + if len(s.ProtoV5ProviderFactories) > 0 { + return true + } + + if len(s.ProtoV6ProviderFactories) > 0 { + return true + } + + if len(s.ProviderFactories) > 0 { + return true + } + + return false +} + +// validate ensures the TestStep is valid based on the following criteria: +// +// - Config or ImportState or RefreshState is set. +// - Config and RefreshState are not both set. +// - RefreshState and Destroy are not both set. +// - RefreshState is not the first TestStep. +// - Providers are not specified (ExternalProviders, +// ProtoV5ProviderFactories, ProtoV6ProviderFactories, ProviderFactories) +// if specified at the TestCase level. +// - Providers are specified (ExternalProviders, ProtoV5ProviderFactories, +// ProtoV6ProviderFactories, ProviderFactories) if not specified at the +// TestCase level. +// - No overlapping ExternalProviders and ProviderFactories entries +// - ResourceName is not empty when ImportState is true, ImportStateIdFunc +// is not set, and ImportStateId is not set. +func (s TestStep) validate(ctx context.Context, req testStepValidateRequest) error { + ctx = logging.TestStepNumberContext(ctx, req.StepNumber) + + logging.HelperResourceTrace(ctx, "Validating TestStep") + + if s.Config == "" && !s.ImportState && !s.RefreshState { + err := fmt.Errorf("TestStep missing Config or ImportState or RefreshState") + logging.HelperResourceError(ctx, "TestStep validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + + if s.Config != "" && s.RefreshState { + err := fmt.Errorf("TestStep cannot have Config and RefreshState") + logging.HelperResourceError(ctx, "TestStep validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + + if s.RefreshState && s.Destroy { + err := fmt.Errorf("TestStep cannot have RefreshState and Destroy") + logging.HelperResourceError(ctx, "TestStep validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + + if s.RefreshState && req.StepNumber == 1 { + err := fmt.Errorf("TestStep cannot have RefreshState as first step") + logging.HelperResourceError(ctx, "TestStep validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + + if s.ImportState && s.RefreshState { + err := fmt.Errorf("TestStep cannot have ImportState and RefreshState in same step") + logging.HelperResourceError(ctx, "TestStep validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + + for name := range s.ExternalProviders { + if _, ok := s.ProviderFactories[name]; ok { + err := fmt.Errorf("TestStep provider %q set in both ExternalProviders and ProviderFactories", name) + logging.HelperResourceError(ctx, "TestStep validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + } + + hasProviders := s.hasProviders(ctx) + + if req.TestCaseHasProviders && hasProviders { + err := fmt.Errorf("Providers must only be specified either at the TestCase or TestStep level") + logging.HelperResourceError(ctx, "TestStep validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + + if !req.TestCaseHasProviders && !hasProviders { + err := fmt.Errorf("Providers must be specified at the TestCase level or in all TestStep") + logging.HelperResourceError(ctx, "TestStep validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + + if s.ImportState { + if s.ImportStateId == "" && s.ImportStateIdFunc == nil && s.ResourceName == "" { + err := fmt.Errorf("TestStep ImportState must be specified with ImportStateId, ImportStateIdFunc, or ResourceName") + logging.HelperResourceError(ctx, "TestStep validation error", map[string]interface{}{logging.KeyError: err}) + return err + } + } + + return nil +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/config.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/config.go new file mode 100644 index 00000000000..d3cb35bcec9 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/config.go @@ -0,0 +1,95 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plugintest + +import ( + "context" + "fmt" + "os" + "strings" + + "github.com/hashicorp/go-version" + install "github.com/hashicorp/hc-install" + "github.com/hashicorp/hc-install/checkpoint" + "github.com/hashicorp/hc-install/fs" + "github.com/hashicorp/hc-install/product" + "github.com/hashicorp/hc-install/releases" + "github.com/hashicorp/hc-install/src" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" +) + +// Config is used to configure the test helper. In most normal test programs +// the configuration is discovered automatically by an Init* function using +// DiscoverConfig, but this is exposed so that more complex scenarios can be +// implemented by direct configuration. +type Config struct { + SourceDir string + TerraformExec string + execTempDir string + PreviousPluginExec string +} + +// DiscoverConfig uses environment variables and other means to automatically +// discover a reasonable test helper configuration. +func DiscoverConfig(ctx context.Context, sourceDir string) (*Config, error) { + tfVersion := strings.TrimPrefix(os.Getenv(EnvTfAccTerraformVersion), "v") + tfPath := os.Getenv(EnvTfAccTerraformPath) + + tempDir := os.Getenv(EnvTfAccTempDir) + tfDir, err := os.MkdirTemp(tempDir, "plugintest-terraform") + if err != nil { + return nil, fmt.Errorf("failed to create temp dir: %w", err) + } + + var sources []src.Source + switch { + case tfPath != "": + logging.HelperResourceTrace(ctx, fmt.Sprintf("Adding potential Terraform CLI source of exact path: %s", tfPath)) + + sources = append(sources, &fs.AnyVersion{ + ExactBinPath: tfPath, + }) + case tfVersion != "": + tfVersion, err := version.NewVersion(tfVersion) + + if err != nil { + return nil, fmt.Errorf("invalid Terraform version: %w", err) + } + + logging.HelperResourceTrace(ctx, fmt.Sprintf("Adding potential Terraform CLI source of releases.hashicorp.com exact version %q for installation in: %s", tfVersion, tfDir)) + + sources = append(sources, &releases.ExactVersion{ + InstallDir: tfDir, + Product: product.Terraform, + Version: tfVersion, + }) + default: + logging.HelperResourceTrace(ctx, "Adding potential Terraform CLI source of local filesystem PATH lookup") + logging.HelperResourceTrace(ctx, fmt.Sprintf("Adding potential Terraform CLI source of checkpoint.hashicorp.com latest version for installation in: %s", tfDir)) + + sources = append(sources, &fs.AnyVersion{ + Product: &product.Terraform, + }) + sources = append(sources, &checkpoint.LatestVersion{ + InstallDir: tfDir, + Product: product.Terraform, + }) + } + + installer := install.NewInstaller() + tfExec, err := installer.Ensure(context.Background(), sources) + if err != nil { + return nil, fmt.Errorf("failed to find or install Terraform CLI from %+v: %w", sources, err) + } + + ctx = logging.TestTerraformPathContext(ctx, tfExec) + + logging.HelperResourceDebug(ctx, "Found Terraform CLI") + + return &Config{ + SourceDir: sourceDir, + TerraformExec: tfExec, + execTempDir: tfDir, + }, nil +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/doc.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/doc.go new file mode 100644 index 00000000000..1b34a0b233e --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/doc.go @@ -0,0 +1,10 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Package plugintest contains utilities to help with writing tests for +// Terraform plugins. +// +// This is not a package for testing configurations or modules written in the +// Terraform language. It is for testing the plugins that allow Terraform to +// manage various cloud services and other APIs. +package plugintest diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/environment_variables.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/environment_variables.go new file mode 100644 index 00000000000..6df86f89f8c --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/environment_variables.go @@ -0,0 +1,111 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plugintest + +// Environment variables +const ( + // Environment variable with acceptance testing temporary directory for + // testing files and Terraform CLI installation, if installation is + // required. By default, the operating system temporary directory is used. + // + // Setting TF_ACC_TERRAFORM_PATH does not override this value for Terraform + // CLI installation, if installation is required. + EnvTfAccTempDir = "TF_ACC_TEMP_DIR" + + // Environment variable with level to filter Terraform logs during + // acceptance testing. This value sets TF_LOG in a safe manner when + // executing Terraform CLI commands, which would otherwise interfere + // with the testing framework using TF_LOG to set the Go standard library + // log package level. + // + // This value takes precedence over TF_LOG_CORE, due to precedence rules + // in the Terraform core code, so it is not possible to set this to a level + // and also TF_LOG_CORE=OFF. Use TF_LOG_CORE and TF_LOG_PROVIDER in that + // case instead. + // + // If not set, but TF_ACC_LOG_PATH or TF_LOG_PATH_MASK is set, it defaults + // to TRACE. If Terraform CLI is version 0.14 or earlier, it will have no + // separate affect from the TF_ACC_LOG_PATH or TF_LOG_PATH_MASK behavior, + // as those earlier versions of Terraform are unreliable with the logging + // level being outside TRACE. + EnvTfAccLog = "TF_ACC_LOG" + + // Environment variable with path to save Terraform logs during acceptance + // testing. This value sets TF_LOG_PATH in a safe manner when executing + // Terraform CLI commands, which would otherwise be ignored since it could + // interfere with how the underlying execution is performed. + // + // If TF_LOG_PATH_MASK is set, it takes precedence over this value. + EnvTfAccLogPath = "TF_ACC_LOG_PATH" + + // Environment variable with level to filter Terraform core logs during + // acceptance testing. This value sets TF_LOG_CORE separate from + // TF_LOG_PROVIDER when calling Terraform. + // + // This value has no affect when TF_ACC_LOG is set (which sets Terraform's + // TF_LOG), due to precedence rules in the Terraform core code. Use + // TF_LOG_CORE and TF_LOG_PROVIDER in that case instead. + // + // If not set, defaults to TF_ACC_LOG behaviors. + EnvTfLogCore = "TF_LOG_CORE" + + // Environment variable with path containing the string %s, which is + // replaced with the test name, to save separate Terraform logs during + // acceptance testing. This value sets TF_LOG_PATH in a safe manner when + // executing Terraform CLI commands, which would otherwise be ignored since + // it could interfere with how the underlying execution is performed. + // + // Takes precedence over TF_ACC_LOG_PATH. + EnvTfLogPathMask = "TF_LOG_PATH_MASK" + + // Environment variable with level to filter Terraform provider logs during + // acceptance testing. This value sets TF_LOG_PROVIDER separate from + // TF_LOG_CORE. + // + // During testing, this only affects external providers whose logging goes + // through Terraform. The logging for the provider under test is controlled + // by the testing framework as it is running the provider code. Provider + // code using the Go standard library log package is controlled by TF_LOG + // for historical compatibility. + // + // This value takes precedence over TF_ACC_LOG for external provider logs, + // due to rules in the Terraform core code. + // + // If not set, defaults to TF_ACC_LOG behaviors. + EnvTfLogProvider = "TF_LOG_PROVIDER" + + // Environment variable with acceptance testing Terraform CLI version to + // download from releases.hashicorp.com, checksum verify, and install. The + // value can be any valid Terraform CLI version, such as 1.1.6, with or + // without a prepended v character. + // + // Setting this value takes precedence over using an available Terraform + // binary in the operation system PATH, or if not found, installing the + // latest version according to checkpoint.hashicorp.com. + // + // By default, the binary is installed in the operating system temporary + // directory, however that directory can be overridden with the + // TF_ACC_TEMP_DIR environment variable. + // + // If TF_ACC_TERRAFORM_PATH is also set, this installation method is + // only invoked when a binary does not exist at that path. No version + // checks are performed against an existing TF_ACC_TERRAFORM_PATH. + EnvTfAccTerraformVersion = "TF_ACC_TERRAFORM_VERSION" + + // Acceptance testing path to Terraform CLI binary. + // + // Setting this value takes precedence over using an available Terraform + // binary in the operation system PATH, or if not found, installing the + // latest version according to checkpoint.hashicorp.com. This value does + // not override TF_ACC_TEMP_DIR for Terraform CLI installation, if + // installation is required. + // + // If TF_ACC_TERRAFORM_VERSION is not set, the binary must exist and be + // executable, or an error will be returned. + // + // If TF_ACC_TERRAFORM_VERSION is also set, that Terraform CLI version + // will be installed if a binary is not found at the given path. No version + // checks are performed against an existing binary. + EnvTfAccTerraformPath = "TF_ACC_TERRAFORM_PATH" +) diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/guard.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/guard.go new file mode 100644 index 00000000000..77f87398009 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/guard.go @@ -0,0 +1,52 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plugintest + +import ( + "fmt" +) + +// TestControl is an interface requiring a subset of *testing.T which is used +// by the test guards and helpers in this package. Most callers can simply +// pass their *testing.T value here, but the interface allows other +// implementations to potentially be provided instead, for example to allow +// meta-testing (testing of the test utilities themselves). +// +// This interface also describes the subset of normal test functionality the +// guards and helpers can perform: they can only create log lines, fail tests, +// and skip tests. All other test control is the responsibility of the main +// test code. +type TestControl interface { + Helper() + Log(args ...interface{}) + FailNow() + SkipNow() + Name() string +} + +// testingT wraps a TestControl to recover some of the convenience behaviors +// that would normally come from a real *testing.T, so we can keep TestControl +// small while still having these conveniences. This is an abstraction +// inversion, but accepted because it makes the public API more convenient +// without any considerable disadvantage. +type testingT struct { + TestControl +} + +func (t testingT) Logf(f string, args ...interface{}) { + t.Helper() + t.Log(fmt.Sprintf(f, args...)) +} + +func (t testingT) Fatalf(f string, args ...interface{}) { + t.Helper() + t.Log(fmt.Sprintf(f, args...)) + t.FailNow() +} + +func (t testingT) Skipf(f string, args ...interface{}) { + t.Helper() + t.Log(fmt.Sprintf(f, args...)) + t.SkipNow() +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/helper.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/helper.go new file mode 100644 index 00000000000..f9617887218 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/helper.go @@ -0,0 +1,290 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plugintest + +import ( + "context" + "errors" + "fmt" + "os" + "strings" + + "github.com/hashicorp/terraform-exec/tfexec" + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" +) + +// AutoInitProviderHelper is the main entrypoint for testing provider plugins +// using this package. It is intended to be called during TestMain to prepare +// for provider testing. +// +// AutoInitProviderHelper will discover the location of a current Terraform CLI +// executable to test against, detect whether a prior version of the plugin is +// available for upgrade tests, and then will return an object containing the +// results of that initialization which can then be stored in a global variable +// for use in other tests. +func AutoInitProviderHelper(ctx context.Context, sourceDir string) *Helper { + helper, err := AutoInitHelper(ctx, sourceDir) + if err != nil { + fmt.Fprintf(os.Stderr, "cannot run Terraform provider tests: %s\n", err) + os.Exit(1) + } + return helper +} + +// Helper is intended as a per-package singleton created in TestMain which +// other tests in a package can use to create Terraform execution contexts +type Helper struct { + baseDir string + + // sourceDir is the dir containing the provider source code, needed + // for tests that use fixture files. + sourceDir string + terraformExec string + + // execTempDir is created during DiscoverConfig to store any downloaded + // binaries + execTempDir string +} + +// AutoInitHelper uses the auto-discovery behavior of DiscoverConfig to prepare +// a configuration and then calls InitHelper with it. This is a convenient +// way to get the standard init behavior based on environment variables, and +// callers should use this unless they have an unusual requirement that calls +// for constructing a config in a different way. +func AutoInitHelper(ctx context.Context, sourceDir string) (*Helper, error) { + config, err := DiscoverConfig(ctx, sourceDir) + if err != nil { + return nil, err + } + + return InitHelper(ctx, config) +} + +// InitHelper prepares a testing helper with the given configuration. +// +// For most callers it is sufficient to call AutoInitHelper instead, which +// will construct a configuration automatically based on certain environment +// variables. +// +// If this function returns an error then it may have left some temporary files +// behind in the system's temporary directory. There is currently no way to +// automatically clean those up. +func InitHelper(ctx context.Context, config *Config) (*Helper, error) { + tempDir := os.Getenv(EnvTfAccTempDir) + baseDir, err := os.MkdirTemp(tempDir, "plugintest") + if err != nil { + return nil, fmt.Errorf("failed to create temporary directory for test helper: %s", err) + } + + return &Helper{ + baseDir: baseDir, + sourceDir: config.SourceDir, + terraformExec: config.TerraformExec, + execTempDir: config.execTempDir, + }, nil +} + +// Close cleans up temporary files and directories created to support this +// helper, returning an error if any of the cleanup fails. +// +// Call this before returning from TestMain to minimize the amount of detritus +// left behind in the filesystem after the tests complete. +func (h *Helper) Close() error { + if h.execTempDir != "" { + err := os.RemoveAll(h.execTempDir) + if err != nil { + return err + } + } + return os.RemoveAll(h.baseDir) +} + +// NewWorkingDir creates a new working directory for use in the implementation +// of a single test, returning a WorkingDir object representing that directory. +// +// If the working directory object is not itself closed by the time the test +// program exits, the Close method on the helper itself will attempt to +// delete it. +func (h *Helper) NewWorkingDir(ctx context.Context, t TestControl) (*WorkingDir, error) { + dir, err := os.MkdirTemp(h.baseDir, "work") + if err != nil { + return nil, err + } + + ctx = logging.TestWorkingDirectoryContext(ctx, dir) + + // symlink the provider source files into the config directory + // e.g. testdata + logging.HelperResourceTrace(ctx, "Symlinking source directories to work directory") + err = symlinkDirectoriesOnly(h.sourceDir, dir) + if err != nil { + return nil, err + } + + tf, err := tfexec.NewTerraform(dir, h.terraformExec) + + if err != nil { + return nil, fmt.Errorf("unable to create terraform-exec instance: %w", err) + } + + err = tf.SetDisablePluginTLS(true) + + if err != nil { + return nil, fmt.Errorf("unable to disable terraform-exec plugin TLS: %w", err) + } + + err = tf.SetSkipProviderVerify(true) // Only required for Terraform CLI 0.12.x + + var mismatch *tfexec.ErrVersionMismatch + if err != nil && !errors.As(err, &mismatch) { + return nil, fmt.Errorf("unable to disable terraform-exec provider verification: %w", err) + } + + tfAccLog := os.Getenv(EnvTfAccLog) + tfAccLogPath := os.Getenv(EnvTfAccLogPath) + tfLogCore := os.Getenv(EnvTfLogCore) + tfLogPathMask := os.Getenv(EnvTfLogPathMask) + tfLogProvider := os.Getenv(EnvTfLogProvider) + + if tfAccLog != "" && tfLogCore != "" { + err = fmt.Errorf( + "Invalid environment variable configuration. Cannot set both TF_ACC_LOG and TF_LOG_CORE. " + + "Use TF_LOG_CORE and TF_LOG_PROVIDER to separately control the Terraform CLI logging subsystems. " + + "To control the Go standard library log package for the provider under test, use TF_LOG.", + ) + logging.HelperResourceError(ctx, err.Error()) + return nil, err + } + + if tfAccLog != "" { + logging.HelperResourceTrace( + ctx, + fmt.Sprintf("Setting terraform-exec log level via %s environment variable, if Terraform CLI is version 0.15 or later", EnvTfAccLog), + map[string]interface{}{logging.KeyTestTerraformLogLevel: tfAccLog}, + ) + + err := tf.SetLog(tfAccLog) + + if err != nil { + if !errors.As(err, new(*tfexec.ErrVersionMismatch)) { + logging.HelperResourceError( + ctx, + "Unable to set terraform-exec log level", + map[string]interface{}{logging.KeyError: err.Error()}, + ) + return nil, fmt.Errorf("unable to set terraform-exec log level (%s): %w", tfAccLog, err) + } + + logging.HelperResourceWarn( + ctx, + fmt.Sprintf("Unable to set terraform-exec log level via %s environment variable, as Terraform CLI is version 0.14 or earlier. It will default to TRACE.", EnvTfAccLog), + map[string]interface{}{logging.KeyTestTerraformLogLevel: "TRACE"}, + ) + } + } + + if tfLogCore != "" { + logging.HelperResourceTrace( + ctx, + fmt.Sprintf("Setting terraform-exec core log level via %s environment variable, if Terraform CLI is version 0.15 or later", EnvTfLogCore), + map[string]interface{}{ + logging.KeyTestTerraformLogCoreLevel: tfLogCore, + }, + ) + + err := tf.SetLogCore(tfLogCore) + + if err != nil { + logging.HelperResourceError( + ctx, + "Unable to set terraform-exec core log level", + map[string]interface{}{logging.KeyError: err.Error()}, + ) + return nil, fmt.Errorf("unable to set terraform-exec core log level (%s): %w", tfLogCore, err) + } + } + + if tfLogProvider != "" { + logging.HelperResourceTrace( + ctx, + fmt.Sprintf("Setting terraform-exec provider log level via %s environment variable, if Terraform CLI is version 0.15 or later", EnvTfLogProvider), + map[string]interface{}{ + logging.KeyTestTerraformLogCoreLevel: tfLogProvider, + }, + ) + + err := tf.SetLogProvider(tfLogProvider) + + if err != nil { + logging.HelperResourceError( + ctx, + "Unable to set terraform-exec provider log level", + map[string]interface{}{logging.KeyError: err.Error()}, + ) + return nil, fmt.Errorf("unable to set terraform-exec provider log level (%s): %w", tfLogProvider, err) + } + } + + var logPath, logPathEnvVar string + + if tfAccLogPath != "" { + logPath = tfAccLogPath + logPathEnvVar = EnvTfAccLogPath + } + + // Similar to helper/logging.LogOutput() and + // terraform-plugin-log/tfsdklog.RegisterTestSink(), the TF_LOG_PATH_MASK + // environment variable should take precedence over TF_ACC_LOG_PATH. + if tfLogPathMask != "" { + // Escape special characters which may appear if we have subtests + testName := strings.Replace(t.Name(), "/", "__", -1) + logPath = fmt.Sprintf(tfLogPathMask, testName) + logPathEnvVar = EnvTfLogPathMask + } + + if logPath != "" { + logging.HelperResourceTrace( + ctx, + fmt.Sprintf("Setting terraform-exec log path via %s environment variable", logPathEnvVar), + map[string]interface{}{logging.KeyTestTerraformLogPath: logPath}, + ) + + if err := tf.SetLogPath(logPath); err != nil { + return nil, fmt.Errorf("unable to set terraform-exec log path (%s): %w", logPath, err) + } + } + + return &WorkingDir{ + h: h, + tf: tf, + baseDir: dir, + terraformExec: h.terraformExec, + }, nil +} + +// RequireNewWorkingDir is a variant of NewWorkingDir that takes a TestControl +// object and will immediately fail the running test if the creation of the +// working directory fails. +func (h *Helper) RequireNewWorkingDir(ctx context.Context, t TestControl) *WorkingDir { + t.Helper() + + wd, err := h.NewWorkingDir(ctx, t) + if err != nil { + t := testingT{t} + t.Fatalf("failed to create new working directory: %s", err) + return nil + } + return wd +} + +// WorkingDirectory returns the working directory being used when running tests. +func (h *Helper) WorkingDirectory() string { + return h.baseDir +} + +// TerraformExecPath returns the location of the Terraform CLI executable that +// should be used when running tests. +func (h *Helper) TerraformExecPath() string { + return h.terraformExec +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/util.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/util.go new file mode 100644 index 00000000000..0d4bbe52667 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/util.go @@ -0,0 +1,70 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plugintest + +import ( + "fmt" + "os" + "path/filepath" +) + +func symlinkFile(src string, dest string) error { + err := os.Symlink(src, dest) + + if err != nil { + return fmt.Errorf("unable to symlink %q to %q: %w", src, dest, err) + } + + srcInfo, err := os.Stat(src) + + if err != nil { + return fmt.Errorf("unable to stat %q: %w", src, err) + } + + err = os.Chmod(dest, srcInfo.Mode()) + + if err != nil { + return fmt.Errorf("unable to set %q permissions: %w", dest, err) + } + + return nil +} + +// symlinkDirectoriesOnly finds only the first-level child directories in srcDir +// and symlinks them into destDir. +// Unlike symlinkDir, this is done non-recursively in order to limit the number +// of file descriptors used. +func symlinkDirectoriesOnly(srcDir string, destDir string) error { + srcInfo, err := os.Stat(srcDir) + if err != nil { + return fmt.Errorf("unable to stat source directory %q: %w", srcDir, err) + } + + err = os.MkdirAll(destDir, srcInfo.Mode()) + if err != nil { + return fmt.Errorf("unable to make destination directory %q: %w", destDir, err) + } + + dirEntries, err := os.ReadDir(srcDir) + + if err != nil { + return fmt.Errorf("unable to read source directory %q: %w", srcDir, err) + } + + for _, dirEntry := range dirEntries { + if !dirEntry.IsDir() { + continue + } + + srcPath := filepath.Join(srcDir, dirEntry.Name()) + destPath := filepath.Join(destDir, dirEntry.Name()) + err := symlinkFile(srcPath, destPath) + + if err != nil { + return fmt.Errorf("unable to symlink directory %q to %q: %w", srcPath, destPath, err) + } + } + + return nil +} diff --git a/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/working_dir.go b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/working_dir.go new file mode 100644 index 00000000000..05b02844206 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/working_dir.go @@ -0,0 +1,371 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package plugintest + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + + "github.com/hashicorp/terraform-exec/tfexec" + tfjson "github.com/hashicorp/terraform-json" + + "github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging" +) + +const ( + ConfigFileName = "terraform_plugin_test.tf" + ConfigFileNameJSON = ConfigFileName + ".json" + PlanFileName = "tfplan" +) + +// WorkingDir represents a distinct working directory that can be used for +// running tests. Each test should construct its own WorkingDir by calling +// NewWorkingDir or RequireNewWorkingDir on its package's singleton +// plugintest.Helper. +type WorkingDir struct { + h *Helper + + // baseDir is the root of the working directory tree + baseDir string + + // configFilename is the full filename where the latest configuration + // was stored; empty until SetConfig is called. + configFilename string + + // tf is the instance of tfexec.Terraform used for running Terraform commands + tf *tfexec.Terraform + + // terraformExec is a path to a terraform binary, inherited from Helper + terraformExec string + + // reattachInfo stores the gRPC socket info required for Terraform's + // plugin reattach functionality + reattachInfo tfexec.ReattachInfo +} + +// Close deletes the directories and files created to represent the receiving +// working directory. After this method is called, the working directory object +// is invalid and may no longer be used. +func (wd *WorkingDir) Close() error { + return os.RemoveAll(wd.baseDir) +} + +func (wd *WorkingDir) SetReattachInfo(ctx context.Context, reattachInfo tfexec.ReattachInfo) { + logging.HelperResourceTrace(ctx, "Setting Terraform CLI reattach configuration", map[string]interface{}{"tf_reattach_config": reattachInfo}) + wd.reattachInfo = reattachInfo +} + +func (wd *WorkingDir) UnsetReattachInfo() { + wd.reattachInfo = nil +} + +// GetHelper returns the Helper set on the WorkingDir. +func (wd *WorkingDir) GetHelper() *Helper { + return wd.h +} + +// SetConfig sets a new configuration for the working directory. +// +// This must be called at least once before any call to Init, Plan, Apply, or +// Destroy to establish the configuration. Any previously-set configuration is +// discarded and any saved plan is cleared. +func (wd *WorkingDir) SetConfig(ctx context.Context, cfg string) error { + logging.HelperResourceTrace(ctx, "Setting Terraform configuration", map[string]any{logging.KeyTestTerraformConfiguration: cfg}) + + outFilename := filepath.Join(wd.baseDir, ConfigFileName) + rmFilename := filepath.Join(wd.baseDir, ConfigFileNameJSON) + bCfg := []byte(cfg) + if json.Valid(bCfg) { + outFilename, rmFilename = rmFilename, outFilename + } + if err := os.Remove(rmFilename); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("unable to remove %q: %w", rmFilename, err) + } + err := os.WriteFile(outFilename, bCfg, 0700) + if err != nil { + return err + } + wd.configFilename = outFilename + + // Changing configuration invalidates any saved plan. + err = wd.ClearPlan(ctx) + if err != nil { + return err + } + return nil +} + +// ClearState deletes any Terraform state present in the working directory. +// +// Any remote objects tracked by the state are not destroyed first, so this +// will leave them dangling in the remote system. +func (wd *WorkingDir) ClearState(ctx context.Context) error { + logging.HelperResourceTrace(ctx, "Clearing Terraform state") + + err := os.Remove(filepath.Join(wd.baseDir, "terraform.tfstate")) + + if os.IsNotExist(err) { + logging.HelperResourceTrace(ctx, "No Terraform state to clear") + return nil + } + + if err != nil { + return err + } + + logging.HelperResourceTrace(ctx, "Cleared Terraform state") + + return nil +} + +// ClearPlan deletes any saved plan present in the working directory. +func (wd *WorkingDir) ClearPlan(ctx context.Context) error { + logging.HelperResourceTrace(ctx, "Clearing Terraform plan") + + err := os.Remove(wd.planFilename()) + + if os.IsNotExist(err) { + logging.HelperResourceTrace(ctx, "No Terraform plan to clear") + return nil + } + + if err != nil { + return err + } + + logging.HelperResourceTrace(ctx, "Cleared Terraform plan") + + return nil +} + +var errWorkingDirSetConfigNotCalled = fmt.Errorf("must call SetConfig before Init") + +// Init runs "terraform init" for the given working directory, forcing Terraform +// to use the current version of the plugin under test. +func (wd *WorkingDir) Init(ctx context.Context) error { + if wd.configFilename == "" { + return errWorkingDirSetConfigNotCalled + } + if _, err := os.Stat(wd.configFilename); err != nil { + return errWorkingDirSetConfigNotCalled + } + + logging.HelperResourceTrace(ctx, "Calling Terraform CLI init command") + + // -upgrade=true is required for per-TestStep provider version changes + // e.g. TestTest_TestStep_ExternalProviders_DifferentVersions + err := wd.tf.Init(context.Background(), tfexec.Reattach(wd.reattachInfo), tfexec.Upgrade(true)) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI init command") + + return err +} + +func (wd *WorkingDir) planFilename() string { + return filepath.Join(wd.baseDir, PlanFileName) +} + +// CreatePlan runs "terraform plan" to create a saved plan file, which if successful +// will then be used for the next call to Apply. +func (wd *WorkingDir) CreatePlan(ctx context.Context) error { + logging.HelperResourceTrace(ctx, "Calling Terraform CLI plan command") + + hasChanges, err := wd.tf.Plan(context.Background(), tfexec.Reattach(wd.reattachInfo), tfexec.Refresh(false), tfexec.Out(PlanFileName)) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI plan command") + + if err != nil { + return err + } + + if !hasChanges { + logging.HelperResourceTrace(ctx, "Created plan with no changes") + + return nil + } + + stdout, err := wd.SavedPlanRawStdout(ctx) + + if err != nil { + return fmt.Errorf("error retrieving formatted plan output: %w", err) + } + + logging.HelperResourceTrace(ctx, "Created plan with changes", map[string]any{logging.KeyTestTerraformPlan: stdout}) + + return nil +} + +// CreateDestroyPlan runs "terraform plan -destroy" to create a saved plan +// file, which if successful will then be used for the next call to Apply. +func (wd *WorkingDir) CreateDestroyPlan(ctx context.Context) error { + logging.HelperResourceTrace(ctx, "Calling Terraform CLI plan -destroy command") + + hasChanges, err := wd.tf.Plan(context.Background(), tfexec.Reattach(wd.reattachInfo), tfexec.Refresh(false), tfexec.Out(PlanFileName), tfexec.Destroy(true)) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI plan -destroy command") + + if err != nil { + return err + } + + if !hasChanges { + logging.HelperResourceTrace(ctx, "Created destroy plan with no changes") + + return nil + } + + stdout, err := wd.SavedPlanRawStdout(ctx) + + if err != nil { + return fmt.Errorf("error retrieving formatted plan output: %w", err) + } + + logging.HelperResourceTrace(ctx, "Created destroy plan with changes", map[string]any{logging.KeyTestTerraformPlan: stdout}) + + return nil +} + +// Apply runs "terraform apply". If CreatePlan has previously completed +// successfully and the saved plan has not been cleared in the meantime then +// this will apply the saved plan. Otherwise, it will implicitly create a new +// plan and apply it. +func (wd *WorkingDir) Apply(ctx context.Context) error { + args := []tfexec.ApplyOption{tfexec.Reattach(wd.reattachInfo), tfexec.Refresh(false)} + if wd.HasSavedPlan() { + args = append(args, tfexec.DirOrPlan(PlanFileName)) + } + + logging.HelperResourceTrace(ctx, "Calling Terraform CLI apply command") + + err := wd.tf.Apply(context.Background(), args...) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI apply command") + + return err +} + +// Destroy runs "terraform destroy". It does not consider or modify any saved +// plan, and is primarily for cleaning up at the end of a test run. +// +// If destroy fails then remote objects might still exist, and continue to +// exist after a particular test is concluded. +func (wd *WorkingDir) Destroy(ctx context.Context) error { + logging.HelperResourceTrace(ctx, "Calling Terraform CLI destroy command") + + err := wd.tf.Destroy(context.Background(), tfexec.Reattach(wd.reattachInfo), tfexec.Refresh(false)) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI destroy command") + + return err +} + +// HasSavedPlan returns true if there is a saved plan in the working directory. If +// so, a subsequent call to Apply will apply that saved plan. +func (wd *WorkingDir) HasSavedPlan() bool { + _, err := os.Stat(wd.planFilename()) + return err == nil +} + +// SavedPlan returns an object describing the current saved plan file, if any. +// +// If no plan is saved or if the plan file cannot be read, SavedPlan returns +// an error. +func (wd *WorkingDir) SavedPlan(ctx context.Context) (*tfjson.Plan, error) { + if !wd.HasSavedPlan() { + return nil, fmt.Errorf("there is no current saved plan") + } + + logging.HelperResourceTrace(ctx, "Calling Terraform CLI show command for JSON plan") + + plan, err := wd.tf.ShowPlanFile(context.Background(), wd.planFilename(), tfexec.Reattach(wd.reattachInfo)) + + logging.HelperResourceTrace(ctx, "Calling Terraform CLI show command for JSON plan") + + return plan, err +} + +// SavedPlanRawStdout returns a human readable stdout capture of the current saved plan file, if any. +// +// If no plan is saved or if the plan file cannot be read, SavedPlanRawStdout returns +// an error. +func (wd *WorkingDir) SavedPlanRawStdout(ctx context.Context) (string, error) { + if !wd.HasSavedPlan() { + return "", fmt.Errorf("there is no current saved plan") + } + + logging.HelperResourceTrace(ctx, "Calling Terraform CLI show command for stdout plan") + + stdout, err := wd.tf.ShowPlanFileRaw(context.Background(), wd.planFilename(), tfexec.Reattach(wd.reattachInfo)) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI show command for stdout plan") + + if err != nil { + return "", err + } + + return stdout, nil +} + +// State returns an object describing the current state. +// + +// If the state cannot be read, State returns an error. +func (wd *WorkingDir) State(ctx context.Context) (*tfjson.State, error) { + logging.HelperResourceTrace(ctx, "Calling Terraform CLI show command for JSON state") + + state, err := wd.tf.Show(context.Background(), tfexec.Reattach(wd.reattachInfo)) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI show command for JSON state") + + return state, err +} + +// Import runs terraform import +func (wd *WorkingDir) Import(ctx context.Context, resource, id string) error { + logging.HelperResourceTrace(ctx, "Calling Terraform CLI import command") + + err := wd.tf.Import(context.Background(), resource, id, tfexec.Config(wd.baseDir), tfexec.Reattach(wd.reattachInfo)) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI import command") + + return err +} + +// Taint runs terraform taint +func (wd *WorkingDir) Taint(ctx context.Context, address string) error { + logging.HelperResourceTrace(ctx, "Calling Terraform CLI taint command") + + err := wd.tf.Taint(context.Background(), address) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI taint command") + + return err +} + +// Refresh runs terraform refresh +func (wd *WorkingDir) Refresh(ctx context.Context) error { + logging.HelperResourceTrace(ctx, "Calling Terraform CLI refresh command") + + err := wd.tf.Refresh(context.Background(), tfexec.Reattach(wd.reattachInfo)) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI refresh command") + + return err +} + +// Schemas returns an object describing the provider schemas. +// +// If the schemas cannot be read, Schemas returns an error. +func (wd *WorkingDir) Schemas(ctx context.Context) (*tfjson.ProviderSchemas, error) { + logging.HelperResourceTrace(ctx, "Calling Terraform CLI providers schema command") + + providerSchemas, err := wd.tf.ProvidersSchema(context.Background()) + + logging.HelperResourceTrace(ctx, "Called Terraform CLI providers schema command") + + return providerSchemas, err +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/ca_bundle.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/ca_bundle.go new file mode 100644 index 00000000000..fe31b8bdaa9 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/ca_bundle.go @@ -0,0 +1,45 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CaBundle The contents of the CA bundle (root and intermediate certificates), properties of the CA bundle, and user-provided contextual metadata for the CA bundle. +type CaBundle struct { + + // The OCID of the CA bundle. + Id *string `mandatory:"true" json:"id"` + + // A user-friendly name for the CA bundle. Names are unique within a compartment. Valid characters include uppercase or lowercase letters, numbers, hyphens, underscores, and periods. + Name *string `mandatory:"true" json:"name"` + + // Certificates (in PEM format) in the CA bundle. Can be of arbitrary length. + CaBundlePem *string `mandatory:"true" json:"caBundlePem"` +} + +func (m CaBundle) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CaBundle) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle.go new file mode 100644 index 00000000000..5061d568620 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle.go @@ -0,0 +1,74 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CertificateAuthorityBundle The contents of the certificate, properties of the certificate (and certificate version), and user-provided contextual metadata for the certificate. +type CertificateAuthorityBundle struct { + + // The OCID of the certificate authority (CA). + CertificateAuthorityId *string `mandatory:"true" json:"certificateAuthorityId"` + + // The name of the CA. + CertificateAuthorityName *string `mandatory:"true" json:"certificateAuthorityName"` + + // A unique certificate identifier used in certificate revocation tracking, formatted as octets. + // Example: `03 AC FC FA CC B3 CB 02 B8 F8 DE F5 85 E7 7B FF` + SerialNumber *string `mandatory:"true" json:"serialNumber"` + + // The certificate (in PEM format) for this CA version. + CertificatePem *string `mandatory:"true" json:"certificatePem"` + + // A property indicating when the CA was created, expressed in RFC 3339 (https://tools.ietf.org/html/rfc3339) timestamp format. + // Example: `2019-04-03T21:10:29.600Z` + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The version number of the CA. + VersionNumber *int64 `mandatory:"true" json:"versionNumber"` + + Validity *Validity `mandatory:"true" json:"validity"` + + // A list of rotation states for this CA. + Stages []VersionStageEnum `mandatory:"true" json:"stages"` + + // The certificate chain (in PEM format) for this CA version. + CertChainPem *string `mandatory:"false" json:"certChainPem"` + + // The name of the CA. + VersionName *string `mandatory:"false" json:"versionName"` + + RevocationStatus *RevocationStatus `mandatory:"false" json:"revocationStatus"` +} + +func (m CertificateAuthorityBundle) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CertificateAuthorityBundle) ValidateEnumValue() (bool, error) { + errMessage := []string{} + for _, val := range m.Stages { + if _, ok := GetMappingVersionStageEnum(string(val)); !ok && val != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Stages: %s. Supported values are: %s.", val, strings.Join(GetVersionStageEnumStringValues(), ","))) + } + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle_version_collection.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle_version_collection.go new file mode 100644 index 00000000000..40a797347c5 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle_version_collection.go @@ -0,0 +1,39 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CertificateAuthorityBundleVersionCollection The results of a certificate authority (CA) version search. Results contain CA version summary objects and other data. +type CertificateAuthorityBundleVersionCollection struct { + + // A list of CA version summary objects. + Items []CertificateAuthorityBundleVersionSummary `mandatory:"true" json:"items"` +} + +func (m CertificateAuthorityBundleVersionCollection) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CertificateAuthorityBundleVersionCollection) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle_version_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle_version_summary.go new file mode 100644 index 00000000000..c7550f692e9 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_authority_bundle_version_summary.go @@ -0,0 +1,72 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CertificateAuthorityBundleVersionSummary The properties of a version of a bundle for a certificate authority (CA). Certificate authority bundle version summary objects do not include the actual contents of the certificate. +type CertificateAuthorityBundleVersionSummary struct { + + // The OCID of the certificate authority (CA). + CertificateAuthorityId *string `mandatory:"true" json:"certificateAuthorityId"` + + // An optional property indicating when the CA version was created, expressed in RFC 3339 (https://tools.ietf.org/html/rfc3339) timestamp format. + // Example: `2019-04-03T21:10:29.600Z` + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // The version number of the CA. + VersionNumber *int64 `mandatory:"true" json:"versionNumber"` + + // The name of the CA. + CertificateAuthorityName *string `mandatory:"true" json:"certificateAuthorityName"` + + // A list of rotation states for this CA version. + Stages []VersionStageEnum `mandatory:"true" json:"stages"` + + // A unique certificate identifier used in certificate revocation tracking, formatted as octets. + // Example: `03 AC FC FA CC B3 CB 02 B8 F8 DE F5 85 E7 7B FF` + SerialNumber *string `mandatory:"false" json:"serialNumber"` + + // The name of the CA version. When this value is not null, the name is unique across CA versions for a given CA. + VersionName *string `mandatory:"false" json:"versionName"` + + // An optional property indicating when to delete the CA version, expressed in RFC 3339 (https://tools.ietf.org/html/rfc3339) timestamp format. + // Example: `2019-04-03T21:10:29.600Z` + TimeOfDeletion *common.SDKTime `mandatory:"false" json:"timeOfDeletion"` + + Validity *Validity `mandatory:"false" json:"validity"` + + RevocationStatus *RevocationStatus `mandatory:"false" json:"revocationStatus"` +} + +func (m CertificateAuthorityBundleVersionSummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CertificateAuthorityBundleVersionSummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + for _, val := range m.Stages { + if _, ok := GetMappingVersionStageEnum(string(val)); !ok && val != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Stages: %s. Supported values are: %s.", val, strings.Join(GetVersionStageEnumStringValues(), ","))) + } + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle.go new file mode 100644 index 00000000000..5857005b2b0 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle.go @@ -0,0 +1,238 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "encoding/json" + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CertificateBundle The contents of the certificate, properties of the certificate (and certificate version), and user-provided contextual metadata for the certificate. +type CertificateBundle interface { + + // The OCID of the certificate. + GetCertificateId() *string + + // The name of the certificate. + GetCertificateName() *string + + // The version number of the certificate. + GetVersionNumber() *int64 + + // A unique certificate identifier used in certificate revocation tracking, formatted as octets. + // Example: `03 AC FC FA CC B3 CB 02 B8 F8 DE F5 85 E7 7B FF` + GetSerialNumber() *string + + // An optional property indicating when the certificate version was created, expressed in RFC 3339 (https://tools.ietf.org/html/rfc3339) timestamp format. + // Example: `2019-04-03T21:10:29.600Z` + GetTimeCreated() *common.SDKTime + + GetValidity() *Validity + + // A list of rotation states for the certificate bundle. + GetStages() []VersionStageEnum + + // The certificate in PEM format. + GetCertificatePem() *string + + // The certificate chain (in PEM format) for the certificate bundle. + GetCertChainPem() *string + + // The name of the certificate version. + GetVersionName() *string + + GetRevocationStatus() *RevocationStatus +} + +type certificatebundle struct { + JsonData []byte + CertificatePem *string `mandatory:"false" json:"certificatePem"` + CertChainPem *string `mandatory:"false" json:"certChainPem"` + VersionName *string `mandatory:"false" json:"versionName"` + RevocationStatus *RevocationStatus `mandatory:"false" json:"revocationStatus"` + CertificateId *string `mandatory:"true" json:"certificateId"` + CertificateName *string `mandatory:"true" json:"certificateName"` + VersionNumber *int64 `mandatory:"true" json:"versionNumber"` + SerialNumber *string `mandatory:"true" json:"serialNumber"` + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + Validity *Validity `mandatory:"true" json:"validity"` + Stages []VersionStageEnum `mandatory:"true" json:"stages"` + CertificateBundleType string `json:"certificateBundleType"` +} + +// UnmarshalJSON unmarshals json +func (m *certificatebundle) UnmarshalJSON(data []byte) error { + m.JsonData = data + type Unmarshalercertificatebundle certificatebundle + s := struct { + Model Unmarshalercertificatebundle + }{} + err := json.Unmarshal(data, &s.Model) + if err != nil { + return err + } + m.CertificateId = s.Model.CertificateId + m.CertificateName = s.Model.CertificateName + m.VersionNumber = s.Model.VersionNumber + m.SerialNumber = s.Model.SerialNumber + m.TimeCreated = s.Model.TimeCreated + m.Validity = s.Model.Validity + m.Stages = s.Model.Stages + m.CertificatePem = s.Model.CertificatePem + m.CertChainPem = s.Model.CertChainPem + m.VersionName = s.Model.VersionName + m.RevocationStatus = s.Model.RevocationStatus + m.CertificateBundleType = s.Model.CertificateBundleType + + return err +} + +// UnmarshalPolymorphicJSON unmarshals polymorphic json +func (m *certificatebundle) UnmarshalPolymorphicJSON(data []byte) (interface{}, error) { + + if data == nil || string(data) == "null" { + return nil, nil + } + + var err error + switch m.CertificateBundleType { + case "CERTIFICATE_CONTENT_PUBLIC_ONLY": + mm := CertificateBundlePublicOnly{} + err = json.Unmarshal(data, &mm) + return mm, err + case "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY": + mm := CertificateBundleWithPrivateKey{} + err = json.Unmarshal(data, &mm) + return mm, err + default: + common.Logf("Received unsupported enum value for CertificateBundle: %s.", m.CertificateBundleType) + return *m, nil + } +} + +// GetCertificatePem returns CertificatePem +func (m certificatebundle) GetCertificatePem() *string { + return m.CertificatePem +} + +// GetCertChainPem returns CertChainPem +func (m certificatebundle) GetCertChainPem() *string { + return m.CertChainPem +} + +// GetVersionName returns VersionName +func (m certificatebundle) GetVersionName() *string { + return m.VersionName +} + +// GetRevocationStatus returns RevocationStatus +func (m certificatebundle) GetRevocationStatus() *RevocationStatus { + return m.RevocationStatus +} + +// GetCertificateId returns CertificateId +func (m certificatebundle) GetCertificateId() *string { + return m.CertificateId +} + +// GetCertificateName returns CertificateName +func (m certificatebundle) GetCertificateName() *string { + return m.CertificateName +} + +// GetVersionNumber returns VersionNumber +func (m certificatebundle) GetVersionNumber() *int64 { + return m.VersionNumber +} + +// GetSerialNumber returns SerialNumber +func (m certificatebundle) GetSerialNumber() *string { + return m.SerialNumber +} + +// GetTimeCreated returns TimeCreated +func (m certificatebundle) GetTimeCreated() *common.SDKTime { + return m.TimeCreated +} + +// GetValidity returns Validity +func (m certificatebundle) GetValidity() *Validity { + return m.Validity +} + +// GetStages returns Stages +func (m certificatebundle) GetStages() []VersionStageEnum { + return m.Stages +} + +func (m certificatebundle) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m certificatebundle) ValidateEnumValue() (bool, error) { + errMessage := []string{} + for _, val := range m.Stages { + if _, ok := GetMappingVersionStageEnum(string(val)); !ok && val != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Stages: %s. Supported values are: %s.", val, strings.Join(GetVersionStageEnumStringValues(), ","))) + } + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// CertificateBundleCertificateBundleTypeEnum Enum with underlying type: string +type CertificateBundleCertificateBundleTypeEnum string + +// Set of constants representing the allowable values for CertificateBundleCertificateBundleTypeEnum +const ( + CertificateBundleCertificateBundleTypePublicOnly CertificateBundleCertificateBundleTypeEnum = "CERTIFICATE_CONTENT_PUBLIC_ONLY" + CertificateBundleCertificateBundleTypeWithPrivateKey CertificateBundleCertificateBundleTypeEnum = "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY" +) + +var mappingCertificateBundleCertificateBundleTypeEnum = map[string]CertificateBundleCertificateBundleTypeEnum{ + "CERTIFICATE_CONTENT_PUBLIC_ONLY": CertificateBundleCertificateBundleTypePublicOnly, + "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY": CertificateBundleCertificateBundleTypeWithPrivateKey, +} + +var mappingCertificateBundleCertificateBundleTypeEnumLowerCase = map[string]CertificateBundleCertificateBundleTypeEnum{ + "certificate_content_public_only": CertificateBundleCertificateBundleTypePublicOnly, + "certificate_content_with_private_key": CertificateBundleCertificateBundleTypeWithPrivateKey, +} + +// GetCertificateBundleCertificateBundleTypeEnumValues Enumerates the set of values for CertificateBundleCertificateBundleTypeEnum +func GetCertificateBundleCertificateBundleTypeEnumValues() []CertificateBundleCertificateBundleTypeEnum { + values := make([]CertificateBundleCertificateBundleTypeEnum, 0) + for _, v := range mappingCertificateBundleCertificateBundleTypeEnum { + values = append(values, v) + } + return values +} + +// GetCertificateBundleCertificateBundleTypeEnumStringValues Enumerates the set of values in String for CertificateBundleCertificateBundleTypeEnum +func GetCertificateBundleCertificateBundleTypeEnumStringValues() []string { + return []string{ + "CERTIFICATE_CONTENT_PUBLIC_ONLY", + "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY", + } +} + +// GetMappingCertificateBundleCertificateBundleTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingCertificateBundleCertificateBundleTypeEnum(val string) (CertificateBundleCertificateBundleTypeEnum, bool) { + enum, ok := mappingCertificateBundleCertificateBundleTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_public_only.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_public_only.go new file mode 100644 index 00000000000..1311f388132 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_public_only.go @@ -0,0 +1,145 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "encoding/json" + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CertificateBundlePublicOnly A certificate bundle, not including the private key. +type CertificateBundlePublicOnly struct { + + // The OCID of the certificate. + CertificateId *string `mandatory:"true" json:"certificateId"` + + // The name of the certificate. + CertificateName *string `mandatory:"true" json:"certificateName"` + + // The version number of the certificate. + VersionNumber *int64 `mandatory:"true" json:"versionNumber"` + + // A unique certificate identifier used in certificate revocation tracking, formatted as octets. + // Example: `03 AC FC FA CC B3 CB 02 B8 F8 DE F5 85 E7 7B FF` + SerialNumber *string `mandatory:"true" json:"serialNumber"` + + // An optional property indicating when the certificate version was created, expressed in RFC 3339 (https://tools.ietf.org/html/rfc3339) timestamp format. + // Example: `2019-04-03T21:10:29.600Z` + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + Validity *Validity `mandatory:"true" json:"validity"` + + // The certificate in PEM format. + CertificatePem *string `mandatory:"false" json:"certificatePem"` + + // The certificate chain (in PEM format) for the certificate bundle. + CertChainPem *string `mandatory:"false" json:"certChainPem"` + + // The name of the certificate version. + VersionName *string `mandatory:"false" json:"versionName"` + + RevocationStatus *RevocationStatus `mandatory:"false" json:"revocationStatus"` + + // A list of rotation states for the certificate bundle. + Stages []VersionStageEnum `mandatory:"true" json:"stages"` +} + +// GetCertificateId returns CertificateId +func (m CertificateBundlePublicOnly) GetCertificateId() *string { + return m.CertificateId +} + +// GetCertificateName returns CertificateName +func (m CertificateBundlePublicOnly) GetCertificateName() *string { + return m.CertificateName +} + +// GetVersionNumber returns VersionNumber +func (m CertificateBundlePublicOnly) GetVersionNumber() *int64 { + return m.VersionNumber +} + +// GetSerialNumber returns SerialNumber +func (m CertificateBundlePublicOnly) GetSerialNumber() *string { + return m.SerialNumber +} + +// GetCertificatePem returns CertificatePem +func (m CertificateBundlePublicOnly) GetCertificatePem() *string { + return m.CertificatePem +} + +// GetCertChainPem returns CertChainPem +func (m CertificateBundlePublicOnly) GetCertChainPem() *string { + return m.CertChainPem +} + +// GetTimeCreated returns TimeCreated +func (m CertificateBundlePublicOnly) GetTimeCreated() *common.SDKTime { + return m.TimeCreated +} + +// GetValidity returns Validity +func (m CertificateBundlePublicOnly) GetValidity() *Validity { + return m.Validity +} + +// GetVersionName returns VersionName +func (m CertificateBundlePublicOnly) GetVersionName() *string { + return m.VersionName +} + +// GetStages returns Stages +func (m CertificateBundlePublicOnly) GetStages() []VersionStageEnum { + return m.Stages +} + +// GetRevocationStatus returns RevocationStatus +func (m CertificateBundlePublicOnly) GetRevocationStatus() *RevocationStatus { + return m.RevocationStatus +} + +func (m CertificateBundlePublicOnly) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CertificateBundlePublicOnly) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + for _, val := range m.Stages { + if _, ok := GetMappingVersionStageEnum(string(val)); !ok && val != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Stages: %s. Supported values are: %s.", val, strings.Join(GetVersionStageEnumStringValues(), ","))) + } + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// MarshalJSON marshals to json representation +func (m CertificateBundlePublicOnly) MarshalJSON() (buff []byte, e error) { + type MarshalTypeCertificateBundlePublicOnly CertificateBundlePublicOnly + s := struct { + DiscriminatorParam string `json:"certificateBundleType"` + MarshalTypeCertificateBundlePublicOnly + }{ + "CERTIFICATE_CONTENT_PUBLIC_ONLY", + (MarshalTypeCertificateBundlePublicOnly)(m), + } + + return json.Marshal(&s) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_version_collection.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_version_collection.go new file mode 100644 index 00000000000..07b4644d762 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_version_collection.go @@ -0,0 +1,39 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CertificateBundleVersionCollection The results of a certificate bundle versions search. Results contain certificate bundle version summary objects. +type CertificateBundleVersionCollection struct { + + // A list of certificate bundle version summary objects. + Items []CertificateBundleVersionSummary `mandatory:"true" json:"items"` +} + +func (m CertificateBundleVersionCollection) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CertificateBundleVersionCollection) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_version_summary.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_version_summary.go new file mode 100644 index 00000000000..5e5d38ae270 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_version_summary.go @@ -0,0 +1,72 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CertificateBundleVersionSummary The properties of the certificate bundle. Certificate bundle version summary objects do not include the actual contents of the certificate. +type CertificateBundleVersionSummary struct { + + // The OCID of the certificate. + CertificateId *string `mandatory:"true" json:"certificateId"` + + // The name of the certificate. + CertificateName *string `mandatory:"true" json:"certificateName"` + + // The version number of the certificate. + VersionNumber *int64 `mandatory:"true" json:"versionNumber"` + + // An optional property indicating when the certificate version was created, expressed in RFC 3339 (https://tools.ietf.org/html/rfc3339) timestamp format. + // Example: `2019-04-03T21:10:29.600Z` + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + // A list of rotation states for this certificate bundle version. + Stages []VersionStageEnum `mandatory:"true" json:"stages"` + + // A unique certificate identifier used in certificate revocation tracking, formatted as octets. + // Example: `03 AC FC FA CC B3 CB 02 B8 F8 DE F5 85 E7 7B FF` + SerialNumber *string `mandatory:"false" json:"serialNumber"` + + // The name of the certificate version. + VersionName *string `mandatory:"false" json:"versionName"` + + Validity *Validity `mandatory:"false" json:"validity"` + + // An optional property indicating when to delete the certificate version, expressed in RFC 3339 (https://tools.ietf.org/html/rfc3339) timestamp format. + // Example: `2019-04-03T21:10:29.600Z` + TimeOfDeletion *common.SDKTime `mandatory:"false" json:"timeOfDeletion"` + + RevocationStatus *RevocationStatus `mandatory:"false" json:"revocationStatus"` +} + +func (m CertificateBundleVersionSummary) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CertificateBundleVersionSummary) ValidateEnumValue() (bool, error) { + errMessage := []string{} + for _, val := range m.Stages { + if _, ok := GetMappingVersionStageEnum(string(val)); !ok && val != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Stages: %s. Supported values are: %s.", val, strings.Join(GetVersionStageEnumStringValues(), ","))) + } + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_with_private_key.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_with_private_key.go new file mode 100644 index 00000000000..4f475521142 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificate_bundle_with_private_key.go @@ -0,0 +1,151 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "encoding/json" + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// CertificateBundleWithPrivateKey A certificate bundle, including the private key. +type CertificateBundleWithPrivateKey struct { + + // The OCID of the certificate. + CertificateId *string `mandatory:"true" json:"certificateId"` + + // The name of the certificate. + CertificateName *string `mandatory:"true" json:"certificateName"` + + // The version number of the certificate. + VersionNumber *int64 `mandatory:"true" json:"versionNumber"` + + // A unique certificate identifier used in certificate revocation tracking, formatted as octets. + // Example: `03 AC FC FA CC B3 CB 02 B8 F8 DE F5 85 E7 7B FF` + SerialNumber *string `mandatory:"true" json:"serialNumber"` + + // An optional property indicating when the certificate version was created, expressed in RFC 3339 (https://tools.ietf.org/html/rfc3339) timestamp format. + // Example: `2019-04-03T21:10:29.600Z` + TimeCreated *common.SDKTime `mandatory:"true" json:"timeCreated"` + + Validity *Validity `mandatory:"true" json:"validity"` + + // The private key (in PEM format) for the certificate. + PrivateKeyPem *string `mandatory:"true" json:"privateKeyPem"` + + // The certificate in PEM format. + CertificatePem *string `mandatory:"false" json:"certificatePem"` + + // The certificate chain (in PEM format) for the certificate bundle. + CertChainPem *string `mandatory:"false" json:"certChainPem"` + + // The name of the certificate version. + VersionName *string `mandatory:"false" json:"versionName"` + + RevocationStatus *RevocationStatus `mandatory:"false" json:"revocationStatus"` + + // An optional passphrase for the private key. + PrivateKeyPemPassphrase *string `mandatory:"false" json:"privateKeyPemPassphrase"` + + // A list of rotation states for the certificate bundle. + Stages []VersionStageEnum `mandatory:"true" json:"stages"` +} + +// GetCertificateId returns CertificateId +func (m CertificateBundleWithPrivateKey) GetCertificateId() *string { + return m.CertificateId +} + +// GetCertificateName returns CertificateName +func (m CertificateBundleWithPrivateKey) GetCertificateName() *string { + return m.CertificateName +} + +// GetVersionNumber returns VersionNumber +func (m CertificateBundleWithPrivateKey) GetVersionNumber() *int64 { + return m.VersionNumber +} + +// GetSerialNumber returns SerialNumber +func (m CertificateBundleWithPrivateKey) GetSerialNumber() *string { + return m.SerialNumber +} + +// GetCertificatePem returns CertificatePem +func (m CertificateBundleWithPrivateKey) GetCertificatePem() *string { + return m.CertificatePem +} + +// GetCertChainPem returns CertChainPem +func (m CertificateBundleWithPrivateKey) GetCertChainPem() *string { + return m.CertChainPem +} + +// GetTimeCreated returns TimeCreated +func (m CertificateBundleWithPrivateKey) GetTimeCreated() *common.SDKTime { + return m.TimeCreated +} + +// GetValidity returns Validity +func (m CertificateBundleWithPrivateKey) GetValidity() *Validity { + return m.Validity +} + +// GetVersionName returns VersionName +func (m CertificateBundleWithPrivateKey) GetVersionName() *string { + return m.VersionName +} + +// GetStages returns Stages +func (m CertificateBundleWithPrivateKey) GetStages() []VersionStageEnum { + return m.Stages +} + +// GetRevocationStatus returns RevocationStatus +func (m CertificateBundleWithPrivateKey) GetRevocationStatus() *RevocationStatus { + return m.RevocationStatus +} + +func (m CertificateBundleWithPrivateKey) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m CertificateBundleWithPrivateKey) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + for _, val := range m.Stages { + if _, ok := GetMappingVersionStageEnum(string(val)); !ok && val != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Stages: %s. Supported values are: %s.", val, strings.Join(GetVersionStageEnumStringValues(), ","))) + } + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// MarshalJSON marshals to json representation +func (m CertificateBundleWithPrivateKey) MarshalJSON() (buff []byte, e error) { + type MarshalTypeCertificateBundleWithPrivateKey CertificateBundleWithPrivateKey + s := struct { + DiscriminatorParam string `json:"certificateBundleType"` + MarshalTypeCertificateBundleWithPrivateKey + }{ + "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY", + (MarshalTypeCertificateBundleWithPrivateKey)(m), + } + + return json.Marshal(&s) +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificates_client.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificates_client.go new file mode 100644 index 00000000000..1322b38c796 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/certificates_client.go @@ -0,0 +1,381 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "context" + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "github.com/oracle/oci-go-sdk/v65/common/auth" + "net/http" +) + +// CertificatesClient a client for Certificates +type CertificatesClient struct { + common.BaseClient + config *common.ConfigurationProvider +} + +// NewCertificatesClientWithConfigurationProvider Creates a new default Certificates client with the given configuration provider. +// the configuration provider will be used for the default signer as well as reading the region +func NewCertificatesClientWithConfigurationProvider(configProvider common.ConfigurationProvider) (client CertificatesClient, err error) { + if enabled := common.CheckForEnabledServices("certificates"); !enabled { + return client, fmt.Errorf("the Developer Tool configuration disabled this service, this behavior is controlled by OciSdkEnabledServicesMap variables. Please check if your local developer-tool-configuration.json file configured the service you're targeting or contact the cloud provider on the availability of this service") + } + provider, err := auth.GetGenericConfigurationProvider(configProvider) + if err != nil { + return client, err + } + baseClient, e := common.NewClientWithConfig(provider) + if e != nil { + return client, e + } + return newCertificatesClientFromBaseClient(baseClient, provider) +} + +// NewCertificatesClientWithOboToken Creates a new default Certificates client with the given configuration provider. +// The obotoken will be added to default headers and signed; the configuration provider will be used for the signer +// +// as well as reading the region +func NewCertificatesClientWithOboToken(configProvider common.ConfigurationProvider, oboToken string) (client CertificatesClient, err error) { + baseClient, err := common.NewClientWithOboToken(configProvider, oboToken) + if err != nil { + return client, err + } + + return newCertificatesClientFromBaseClient(baseClient, configProvider) +} + +func newCertificatesClientFromBaseClient(baseClient common.BaseClient, configProvider common.ConfigurationProvider) (client CertificatesClient, err error) { + // Certificates service default circuit breaker is enabled + baseClient.Configuration.CircuitBreaker = common.NewCircuitBreaker(common.DefaultCircuitBreakerSettingWithServiceName("Certificates")) + common.ConfigCircuitBreakerFromEnvVar(&baseClient) + common.ConfigCircuitBreakerFromGlobalVar(&baseClient) + + client = CertificatesClient{BaseClient: baseClient} + client.BasePath = "20210224" + err = client.setConfigurationProvider(configProvider) + return +} + +// SetRegion overrides the region of this client. +func (client *CertificatesClient) SetRegion(region string) { + client.Host = common.StringToRegion(region).EndpointForTemplate("certificates", "https://certificates.{region}.oci.{secondLevelDomain}") +} + +// SetConfigurationProvider sets the configuration provider including the region, returns an error if is not valid +func (client *CertificatesClient) setConfigurationProvider(configProvider common.ConfigurationProvider) error { + if ok, err := common.IsConfigurationProviderValid(configProvider); !ok { + return err + } + + // Error has been checked already + region, _ := configProvider.Region() + client.SetRegion(region) + if client.Host == "" { + return fmt.Errorf("invalid region or Host. Endpoint cannot be constructed without endpointServiceName or serviceEndpointTemplate for a dotted region") + } + client.config = &configProvider + return nil +} + +// ConfigurationProvider the ConfigurationProvider used in this client, or null if none set +func (client *CertificatesClient) ConfigurationProvider() *common.ConfigurationProvider { + return client.config +} + +// GetCaBundle Gets a ca-bundle bundle. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/certificates/GetCaBundle.go.html to see an example of how to use GetCaBundle API. +func (client CertificatesClient) GetCaBundle(ctx context.Context, request GetCaBundleRequest) (response GetCaBundleResponse, err error) { + var ociResponse common.OCIResponse + policy := common.NoRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getCaBundle, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetCaBundleResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetCaBundleResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetCaBundleResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetCaBundleResponse") + } + return +} + +// getCaBundle implements the OCIOperation interface (enables retrying operations) +func (client CertificatesClient) getCaBundle(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/caBundles/{caBundleId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + var response GetCaBundleResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/certificates/20210224/CaBundle/GetCaBundle" + err = common.PostProcessServiceError(err, "Certificates", "GetCaBundle", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetCertificateAuthorityBundle Gets a certificate authority bundle that matches either the specified `stage`, `name`, or `versionNumber` parameter. +// If none of these parameters are provided, the bundle for the certificate authority version marked as `CURRENT` will be returned. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/certificates/GetCertificateAuthorityBundle.go.html to see an example of how to use GetCertificateAuthorityBundle API. +func (client CertificatesClient) GetCertificateAuthorityBundle(ctx context.Context, request GetCertificateAuthorityBundleRequest) (response GetCertificateAuthorityBundleResponse, err error) { + var ociResponse common.OCIResponse + policy := common.NoRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getCertificateAuthorityBundle, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetCertificateAuthorityBundleResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetCertificateAuthorityBundleResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetCertificateAuthorityBundleResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetCertificateAuthorityBundleResponse") + } + return +} + +// getCertificateAuthorityBundle implements the OCIOperation interface (enables retrying operations) +func (client CertificatesClient) getCertificateAuthorityBundle(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/certificateAuthorityBundles/{certificateAuthorityId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + var response GetCertificateAuthorityBundleResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/certificates/20210224/CertificateAuthorityBundle/GetCertificateAuthorityBundle" + err = common.PostProcessServiceError(err, "Certificates", "GetCertificateAuthorityBundle", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// GetCertificateBundle Gets a certificate bundle that matches either the specified `stage`, `versionName`, or `versionNumber` parameter. +// If none of these parameters are provided, the bundle for the certificate version marked as `CURRENT` will be returned. +// By default, the private key is not included in the query result, and a CertificateBundlePublicOnly is returned. +// If the private key is needed, use the CertificateBundleTypeQueryParam parameter to get a CertificateBundleWithPrivateKey response. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/certificates/GetCertificateBundle.go.html to see an example of how to use GetCertificateBundle API. +func (client CertificatesClient) GetCertificateBundle(ctx context.Context, request GetCertificateBundleRequest) (response GetCertificateBundleResponse, err error) { + var ociResponse common.OCIResponse + policy := common.NoRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.getCertificateBundle, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = GetCertificateBundleResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = GetCertificateBundleResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(GetCertificateBundleResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into GetCertificateBundleResponse") + } + return +} + +// getCertificateBundle implements the OCIOperation interface (enables retrying operations) +func (client CertificatesClient) getCertificateBundle(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/certificateBundles/{certificateId}", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + var response GetCertificateBundleResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/certificates/20210224/CertificateBundle/GetCertificateBundle" + err = common.PostProcessServiceError(err, "Certificates", "GetCertificateBundle", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponseWithPolymorphicBody(httpResponse, &response, &certificatebundle{}) + return response, err +} + +// ListCertificateAuthorityBundleVersions Lists all certificate authority bundle versions for the specified certificate authority. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/certificates/ListCertificateAuthorityBundleVersions.go.html to see an example of how to use ListCertificateAuthorityBundleVersions API. +func (client CertificatesClient) ListCertificateAuthorityBundleVersions(ctx context.Context, request ListCertificateAuthorityBundleVersionsRequest) (response ListCertificateAuthorityBundleVersionsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.NoRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listCertificateAuthorityBundleVersions, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListCertificateAuthorityBundleVersionsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListCertificateAuthorityBundleVersionsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListCertificateAuthorityBundleVersionsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListCertificateAuthorityBundleVersionsResponse") + } + return +} + +// listCertificateAuthorityBundleVersions implements the OCIOperation interface (enables retrying operations) +func (client CertificatesClient) listCertificateAuthorityBundleVersions(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/certificateAuthorityBundles/{certificateAuthorityId}/versions", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + var response ListCertificateAuthorityBundleVersionsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/certificates/20210224/CertificateAuthorityBundleVersionSummary/ListCertificateAuthorityBundleVersions" + err = common.PostProcessServiceError(err, "Certificates", "ListCertificateAuthorityBundleVersions", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} + +// ListCertificateBundleVersions Lists all certificate bundle versions for the specified certificate. +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/certificates/ListCertificateBundleVersions.go.html to see an example of how to use ListCertificateBundleVersions API. +func (client CertificatesClient) ListCertificateBundleVersions(ctx context.Context, request ListCertificateBundleVersionsRequest) (response ListCertificateBundleVersionsResponse, err error) { + var ociResponse common.OCIResponse + policy := common.NoRetryPolicy() + if client.RetryPolicy() != nil { + policy = *client.RetryPolicy() + } + if request.RetryPolicy() != nil { + policy = *request.RetryPolicy() + } + ociResponse, err = common.Retry(ctx, request, client.listCertificateBundleVersions, policy) + if err != nil { + if ociResponse != nil { + if httpResponse := ociResponse.HTTPResponse(); httpResponse != nil { + opcRequestId := httpResponse.Header.Get("opc-request-id") + response = ListCertificateBundleVersionsResponse{RawResponse: httpResponse, OpcRequestId: &opcRequestId} + } else { + response = ListCertificateBundleVersionsResponse{} + } + } + return + } + if convertedResponse, ok := ociResponse.(ListCertificateBundleVersionsResponse); ok { + response = convertedResponse + } else { + err = fmt.Errorf("failed to convert OCIResponse into ListCertificateBundleVersionsResponse") + } + return +} + +// listCertificateBundleVersions implements the OCIOperation interface (enables retrying operations) +func (client CertificatesClient) listCertificateBundleVersions(ctx context.Context, request common.OCIRequest, binaryReqBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (common.OCIResponse, error) { + + httpRequest, err := request.HTTPRequest(http.MethodGet, "/certificateBundles/{certificateId}/versions", binaryReqBody, extraHeaders) + if err != nil { + return nil, err + } + + var response ListCertificateBundleVersionsResponse + var httpResponse *http.Response + httpResponse, err = client.Call(ctx, &httpRequest) + defer common.CloseBodyIfValid(httpResponse) + response.RawResponse = httpResponse + if err != nil { + apiReferenceLink := "https://docs.oracle.com/iaas/api/#/en/certificates/20210224/CertificateBundleVersionSummary/ListCertificateBundleVersions" + err = common.PostProcessServiceError(err, "Certificates", "ListCertificateBundleVersions", apiReferenceLink) + return response, err + } + + err = common.UnmarshalResponse(httpResponse, &response) + return response, err +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_ca_bundle_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_ca_bundle_request_response.go new file mode 100644 index 00000000000..759f1443043 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_ca_bundle_request_response.go @@ -0,0 +1,93 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetCaBundleRequest wrapper for the GetCaBundle operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/certificates/GetCaBundle.go.html to see an example of how to use GetCaBundleRequest. +type GetCaBundleRequest struct { + + // The OCID of the CA bundle. + CaBundleId *string `mandatory:"true" contributesTo:"path" name:"caBundleId"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // please provide the request ID. + OpcRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-request-id"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetCaBundleRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetCaBundleRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetCaBundleRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetCaBundleRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetCaBundleRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetCaBundleResponse wrapper for the GetCaBundle operation +type GetCaBundleResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The CaBundle instance + CaBundle `presentIn:"body"` + + // For optimistic concurrency control. See `if-match`. + Etag *string `presentIn:"header" name:"etag"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, please provide the request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response GetCaBundleResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetCaBundleResponse) HTTPResponse() *http.Response { + return response.RawResponse +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_certificate_authority_bundle_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_certificate_authority_bundle_request_response.go new file mode 100644 index 00000000000..f69a310ab16 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_certificate_authority_bundle_request_response.go @@ -0,0 +1,159 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetCertificateAuthorityBundleRequest wrapper for the GetCertificateAuthorityBundle operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/certificates/GetCertificateAuthorityBundle.go.html to see an example of how to use GetCertificateAuthorityBundleRequest. +type GetCertificateAuthorityBundleRequest struct { + + // The OCID of the certificate authority (CA). + CertificateAuthorityId *string `mandatory:"true" contributesTo:"path" name:"certificateAuthorityId"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // please provide the request ID. + OpcRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-request-id"` + + // The version number of the certificate authority (CA). + VersionNumber *int64 `mandatory:"false" contributesTo:"query" name:"versionNumber"` + + // The name of the certificate authority (CA). (This might be referred to as the name of the CA version, as every CA consists of at least one version.) Names are unique across versions of a given CA. + CertificateAuthorityVersionName *string `mandatory:"false" contributesTo:"query" name:"certificateAuthorityVersionName"` + + // The rotation state of the certificate version. + Stage GetCertificateAuthorityBundleStageEnum `mandatory:"false" contributesTo:"query" name:"stage" omitEmpty:"true"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetCertificateAuthorityBundleRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetCertificateAuthorityBundleRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetCertificateAuthorityBundleRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetCertificateAuthorityBundleRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetCertificateAuthorityBundleRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingGetCertificateAuthorityBundleStageEnum(string(request.Stage)); !ok && request.Stage != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Stage: %s. Supported values are: %s.", request.Stage, strings.Join(GetGetCertificateAuthorityBundleStageEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetCertificateAuthorityBundleResponse wrapper for the GetCertificateAuthorityBundle operation +type GetCertificateAuthorityBundleResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The CertificateAuthorityBundle instance + CertificateAuthorityBundle `presentIn:"body"` + + // For optimistic concurrency control. See `if-match`. + Etag *string `presentIn:"header" name:"etag"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, please provide the request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response GetCertificateAuthorityBundleResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetCertificateAuthorityBundleResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// GetCertificateAuthorityBundleStageEnum Enum with underlying type: string +type GetCertificateAuthorityBundleStageEnum string + +// Set of constants representing the allowable values for GetCertificateAuthorityBundleStageEnum +const ( + GetCertificateAuthorityBundleStageCurrent GetCertificateAuthorityBundleStageEnum = "CURRENT" + GetCertificateAuthorityBundleStagePending GetCertificateAuthorityBundleStageEnum = "PENDING" + GetCertificateAuthorityBundleStageLatest GetCertificateAuthorityBundleStageEnum = "LATEST" + GetCertificateAuthorityBundleStagePrevious GetCertificateAuthorityBundleStageEnum = "PREVIOUS" + GetCertificateAuthorityBundleStageDeprecated GetCertificateAuthorityBundleStageEnum = "DEPRECATED" +) + +var mappingGetCertificateAuthorityBundleStageEnum = map[string]GetCertificateAuthorityBundleStageEnum{ + "CURRENT": GetCertificateAuthorityBundleStageCurrent, + "PENDING": GetCertificateAuthorityBundleStagePending, + "LATEST": GetCertificateAuthorityBundleStageLatest, + "PREVIOUS": GetCertificateAuthorityBundleStagePrevious, + "DEPRECATED": GetCertificateAuthorityBundleStageDeprecated, +} + +var mappingGetCertificateAuthorityBundleStageEnumLowerCase = map[string]GetCertificateAuthorityBundleStageEnum{ + "current": GetCertificateAuthorityBundleStageCurrent, + "pending": GetCertificateAuthorityBundleStagePending, + "latest": GetCertificateAuthorityBundleStageLatest, + "previous": GetCertificateAuthorityBundleStagePrevious, + "deprecated": GetCertificateAuthorityBundleStageDeprecated, +} + +// GetGetCertificateAuthorityBundleStageEnumValues Enumerates the set of values for GetCertificateAuthorityBundleStageEnum +func GetGetCertificateAuthorityBundleStageEnumValues() []GetCertificateAuthorityBundleStageEnum { + values := make([]GetCertificateAuthorityBundleStageEnum, 0) + for _, v := range mappingGetCertificateAuthorityBundleStageEnum { + values = append(values, v) + } + return values +} + +// GetGetCertificateAuthorityBundleStageEnumStringValues Enumerates the set of values in String for GetCertificateAuthorityBundleStageEnum +func GetGetCertificateAuthorityBundleStageEnumStringValues() []string { + return []string{ + "CURRENT", + "PENDING", + "LATEST", + "PREVIOUS", + "DEPRECATED", + } +} + +// GetMappingGetCertificateAuthorityBundleStageEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingGetCertificateAuthorityBundleStageEnum(val string) (GetCertificateAuthorityBundleStageEnum, bool) { + enum, ok := mappingGetCertificateAuthorityBundleStageEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_certificate_bundle_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_certificate_bundle_request_response.go new file mode 100644 index 00000000000..ab007eab765 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/get_certificate_bundle_request_response.go @@ -0,0 +1,207 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// GetCertificateBundleRequest wrapper for the GetCertificateBundle operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/certificates/GetCertificateBundle.go.html to see an example of how to use GetCertificateBundleRequest. +type GetCertificateBundleRequest struct { + + // The OCID of the certificate. + CertificateId *string `mandatory:"true" contributesTo:"path" name:"certificateId"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // please provide the request ID. + OpcRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-request-id"` + + // The version number of the certificate. The default value is 0, which means that this query parameter is ignored. + VersionNumber *int64 `mandatory:"false" contributesTo:"query" name:"versionNumber"` + + // The name of the certificate. (This might be referred to as the name of the certificate version, as every certificate consists of at least one version.) Names are unique across versions of a given certificate. + CertificateVersionName *string `mandatory:"false" contributesTo:"query" name:"certificateVersionName"` + + // The rotation state of the certificate version. + Stage GetCertificateBundleStageEnum `mandatory:"false" contributesTo:"query" name:"stage" omitEmpty:"true"` + + // The type of certificate bundle. By default, the private key fields are not returned. When querying for certificate bundles, to return results with certificate contents, the private key in PEM format, and the private key passphrase, specify the value of this parameter as `CERTIFICATE_CONTENT_WITH_PRIVATE_KEY`. + CertificateBundleType GetCertificateBundleCertificateBundleTypeEnum `mandatory:"false" contributesTo:"query" name:"certificateBundleType" omitEmpty:"true"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request GetCertificateBundleRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request GetCertificateBundleRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request GetCertificateBundleRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request GetCertificateBundleRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request GetCertificateBundleRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingGetCertificateBundleStageEnum(string(request.Stage)); !ok && request.Stage != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for Stage: %s. Supported values are: %s.", request.Stage, strings.Join(GetGetCertificateBundleStageEnumStringValues(), ","))) + } + if _, ok := GetMappingGetCertificateBundleCertificateBundleTypeEnum(string(request.CertificateBundleType)); !ok && request.CertificateBundleType != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for CertificateBundleType: %s. Supported values are: %s.", request.CertificateBundleType, strings.Join(GetGetCertificateBundleCertificateBundleTypeEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// GetCertificateBundleResponse wrapper for the GetCertificateBundle operation +type GetCertificateBundleResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The CertificateBundle instance + CertificateBundle `presentIn:"body"` + + // For optimistic concurrency control. See `if-match`. + Etag *string `presentIn:"header" name:"etag"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, please provide the request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response GetCertificateBundleResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response GetCertificateBundleResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// GetCertificateBundleStageEnum Enum with underlying type: string +type GetCertificateBundleStageEnum string + +// Set of constants representing the allowable values for GetCertificateBundleStageEnum +const ( + GetCertificateBundleStageCurrent GetCertificateBundleStageEnum = "CURRENT" + GetCertificateBundleStagePending GetCertificateBundleStageEnum = "PENDING" + GetCertificateBundleStageLatest GetCertificateBundleStageEnum = "LATEST" + GetCertificateBundleStagePrevious GetCertificateBundleStageEnum = "PREVIOUS" + GetCertificateBundleStageDeprecated GetCertificateBundleStageEnum = "DEPRECATED" +) + +var mappingGetCertificateBundleStageEnum = map[string]GetCertificateBundleStageEnum{ + "CURRENT": GetCertificateBundleStageCurrent, + "PENDING": GetCertificateBundleStagePending, + "LATEST": GetCertificateBundleStageLatest, + "PREVIOUS": GetCertificateBundleStagePrevious, + "DEPRECATED": GetCertificateBundleStageDeprecated, +} + +var mappingGetCertificateBundleStageEnumLowerCase = map[string]GetCertificateBundleStageEnum{ + "current": GetCertificateBundleStageCurrent, + "pending": GetCertificateBundleStagePending, + "latest": GetCertificateBundleStageLatest, + "previous": GetCertificateBundleStagePrevious, + "deprecated": GetCertificateBundleStageDeprecated, +} + +// GetGetCertificateBundleStageEnumValues Enumerates the set of values for GetCertificateBundleStageEnum +func GetGetCertificateBundleStageEnumValues() []GetCertificateBundleStageEnum { + values := make([]GetCertificateBundleStageEnum, 0) + for _, v := range mappingGetCertificateBundleStageEnum { + values = append(values, v) + } + return values +} + +// GetGetCertificateBundleStageEnumStringValues Enumerates the set of values in String for GetCertificateBundleStageEnum +func GetGetCertificateBundleStageEnumStringValues() []string { + return []string{ + "CURRENT", + "PENDING", + "LATEST", + "PREVIOUS", + "DEPRECATED", + } +} + +// GetMappingGetCertificateBundleStageEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingGetCertificateBundleStageEnum(val string) (GetCertificateBundleStageEnum, bool) { + enum, ok := mappingGetCertificateBundleStageEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// GetCertificateBundleCertificateBundleTypeEnum Enum with underlying type: string +type GetCertificateBundleCertificateBundleTypeEnum string + +// Set of constants representing the allowable values for GetCertificateBundleCertificateBundleTypeEnum +const ( + GetCertificateBundleCertificateBundleTypePublicOnly GetCertificateBundleCertificateBundleTypeEnum = "CERTIFICATE_CONTENT_PUBLIC_ONLY" + GetCertificateBundleCertificateBundleTypeWithPrivateKey GetCertificateBundleCertificateBundleTypeEnum = "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY" +) + +var mappingGetCertificateBundleCertificateBundleTypeEnum = map[string]GetCertificateBundleCertificateBundleTypeEnum{ + "CERTIFICATE_CONTENT_PUBLIC_ONLY": GetCertificateBundleCertificateBundleTypePublicOnly, + "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY": GetCertificateBundleCertificateBundleTypeWithPrivateKey, +} + +var mappingGetCertificateBundleCertificateBundleTypeEnumLowerCase = map[string]GetCertificateBundleCertificateBundleTypeEnum{ + "certificate_content_public_only": GetCertificateBundleCertificateBundleTypePublicOnly, + "certificate_content_with_private_key": GetCertificateBundleCertificateBundleTypeWithPrivateKey, +} + +// GetGetCertificateBundleCertificateBundleTypeEnumValues Enumerates the set of values for GetCertificateBundleCertificateBundleTypeEnum +func GetGetCertificateBundleCertificateBundleTypeEnumValues() []GetCertificateBundleCertificateBundleTypeEnum { + values := make([]GetCertificateBundleCertificateBundleTypeEnum, 0) + for _, v := range mappingGetCertificateBundleCertificateBundleTypeEnum { + values = append(values, v) + } + return values +} + +// GetGetCertificateBundleCertificateBundleTypeEnumStringValues Enumerates the set of values in String for GetCertificateBundleCertificateBundleTypeEnum +func GetGetCertificateBundleCertificateBundleTypeEnumStringValues() []string { + return []string{ + "CERTIFICATE_CONTENT_PUBLIC_ONLY", + "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY", + } +} + +// GetMappingGetCertificateBundleCertificateBundleTypeEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingGetCertificateBundleCertificateBundleTypeEnum(val string) (GetCertificateBundleCertificateBundleTypeEnum, bool) { + enum, ok := mappingGetCertificateBundleCertificateBundleTypeEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/list_certificate_authority_bundle_versions_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/list_certificate_authority_bundle_versions_request_response.go new file mode 100644 index 00000000000..fe06e7fb452 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/list_certificate_authority_bundle_versions_request_response.go @@ -0,0 +1,183 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListCertificateAuthorityBundleVersionsRequest wrapper for the ListCertificateAuthorityBundleVersions operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/certificates/ListCertificateAuthorityBundleVersions.go.html to see an example of how to use ListCertificateAuthorityBundleVersionsRequest. +type ListCertificateAuthorityBundleVersionsRequest struct { + + // The OCID of the certificate authority (CA). + CertificateAuthorityId *string `mandatory:"true" contributesTo:"path" name:"certificateAuthorityId"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // please provide the request ID. + OpcRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-request-id"` + + // The field to sort by. You can specify only one sort order. The default + // order for `VERSION_NUMBER` is ascending. + SortBy ListCertificateAuthorityBundleVersionsSortByEnum `mandatory:"false" contributesTo:"query" name:"sortBy" omitEmpty:"true"` + + // The sort order to use, either ascending (`ASC`) or descending (`DESC`). + SortOrder ListCertificateAuthorityBundleVersionsSortOrderEnum `mandatory:"false" contributesTo:"query" name:"sortOrder" omitEmpty:"true"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListCertificateAuthorityBundleVersionsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListCertificateAuthorityBundleVersionsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListCertificateAuthorityBundleVersionsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListCertificateAuthorityBundleVersionsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListCertificateAuthorityBundleVersionsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingListCertificateAuthorityBundleVersionsSortByEnum(string(request.SortBy)); !ok && request.SortBy != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for SortBy: %s. Supported values are: %s.", request.SortBy, strings.Join(GetListCertificateAuthorityBundleVersionsSortByEnumStringValues(), ","))) + } + if _, ok := GetMappingListCertificateAuthorityBundleVersionsSortOrderEnum(string(request.SortOrder)); !ok && request.SortOrder != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for SortOrder: %s. Supported values are: %s.", request.SortOrder, strings.Join(GetListCertificateAuthorityBundleVersionsSortOrderEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListCertificateAuthorityBundleVersionsResponse wrapper for the ListCertificateAuthorityBundleVersions operation +type ListCertificateAuthorityBundleVersionsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The CertificateAuthorityBundleVersionCollection instance + CertificateAuthorityBundleVersionCollection `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, please provide the request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response ListCertificateAuthorityBundleVersionsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListCertificateAuthorityBundleVersionsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// ListCertificateAuthorityBundleVersionsSortByEnum Enum with underlying type: string +type ListCertificateAuthorityBundleVersionsSortByEnum string + +// Set of constants representing the allowable values for ListCertificateAuthorityBundleVersionsSortByEnum +const ( + ListCertificateAuthorityBundleVersionsSortByVersionNumber ListCertificateAuthorityBundleVersionsSortByEnum = "VERSION_NUMBER" +) + +var mappingListCertificateAuthorityBundleVersionsSortByEnum = map[string]ListCertificateAuthorityBundleVersionsSortByEnum{ + "VERSION_NUMBER": ListCertificateAuthorityBundleVersionsSortByVersionNumber, +} + +var mappingListCertificateAuthorityBundleVersionsSortByEnumLowerCase = map[string]ListCertificateAuthorityBundleVersionsSortByEnum{ + "version_number": ListCertificateAuthorityBundleVersionsSortByVersionNumber, +} + +// GetListCertificateAuthorityBundleVersionsSortByEnumValues Enumerates the set of values for ListCertificateAuthorityBundleVersionsSortByEnum +func GetListCertificateAuthorityBundleVersionsSortByEnumValues() []ListCertificateAuthorityBundleVersionsSortByEnum { + values := make([]ListCertificateAuthorityBundleVersionsSortByEnum, 0) + for _, v := range mappingListCertificateAuthorityBundleVersionsSortByEnum { + values = append(values, v) + } + return values +} + +// GetListCertificateAuthorityBundleVersionsSortByEnumStringValues Enumerates the set of values in String for ListCertificateAuthorityBundleVersionsSortByEnum +func GetListCertificateAuthorityBundleVersionsSortByEnumStringValues() []string { + return []string{ + "VERSION_NUMBER", + } +} + +// GetMappingListCertificateAuthorityBundleVersionsSortByEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingListCertificateAuthorityBundleVersionsSortByEnum(val string) (ListCertificateAuthorityBundleVersionsSortByEnum, bool) { + enum, ok := mappingListCertificateAuthorityBundleVersionsSortByEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// ListCertificateAuthorityBundleVersionsSortOrderEnum Enum with underlying type: string +type ListCertificateAuthorityBundleVersionsSortOrderEnum string + +// Set of constants representing the allowable values for ListCertificateAuthorityBundleVersionsSortOrderEnum +const ( + ListCertificateAuthorityBundleVersionsSortOrderAsc ListCertificateAuthorityBundleVersionsSortOrderEnum = "ASC" + ListCertificateAuthorityBundleVersionsSortOrderDesc ListCertificateAuthorityBundleVersionsSortOrderEnum = "DESC" +) + +var mappingListCertificateAuthorityBundleVersionsSortOrderEnum = map[string]ListCertificateAuthorityBundleVersionsSortOrderEnum{ + "ASC": ListCertificateAuthorityBundleVersionsSortOrderAsc, + "DESC": ListCertificateAuthorityBundleVersionsSortOrderDesc, +} + +var mappingListCertificateAuthorityBundleVersionsSortOrderEnumLowerCase = map[string]ListCertificateAuthorityBundleVersionsSortOrderEnum{ + "asc": ListCertificateAuthorityBundleVersionsSortOrderAsc, + "desc": ListCertificateAuthorityBundleVersionsSortOrderDesc, +} + +// GetListCertificateAuthorityBundleVersionsSortOrderEnumValues Enumerates the set of values for ListCertificateAuthorityBundleVersionsSortOrderEnum +func GetListCertificateAuthorityBundleVersionsSortOrderEnumValues() []ListCertificateAuthorityBundleVersionsSortOrderEnum { + values := make([]ListCertificateAuthorityBundleVersionsSortOrderEnum, 0) + for _, v := range mappingListCertificateAuthorityBundleVersionsSortOrderEnum { + values = append(values, v) + } + return values +} + +// GetListCertificateAuthorityBundleVersionsSortOrderEnumStringValues Enumerates the set of values in String for ListCertificateAuthorityBundleVersionsSortOrderEnum +func GetListCertificateAuthorityBundleVersionsSortOrderEnumStringValues() []string { + return []string{ + "ASC", + "DESC", + } +} + +// GetMappingListCertificateAuthorityBundleVersionsSortOrderEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingListCertificateAuthorityBundleVersionsSortOrderEnum(val string) (ListCertificateAuthorityBundleVersionsSortOrderEnum, bool) { + enum, ok := mappingListCertificateAuthorityBundleVersionsSortOrderEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/list_certificate_bundle_versions_request_response.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/list_certificate_bundle_versions_request_response.go new file mode 100644 index 00000000000..5dd3f529e84 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/list_certificate_bundle_versions_request_response.go @@ -0,0 +1,183 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "net/http" + "strings" +) + +// ListCertificateBundleVersionsRequest wrapper for the ListCertificateBundleVersions operation +// +// # See also +// +// Click https://docs.oracle.com/en-us/iaas/tools/go-sdk-examples/latest/certificates/ListCertificateBundleVersions.go.html to see an example of how to use ListCertificateBundleVersionsRequest. +type ListCertificateBundleVersionsRequest struct { + + // The OCID of the certificate. + CertificateId *string `mandatory:"true" contributesTo:"path" name:"certificateId"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, + // please provide the request ID. + OpcRequestId *string `mandatory:"false" contributesTo:"header" name:"opc-request-id"` + + // The field to sort by. You can specify only one sort order. The default + // order for `VERSION_NUMBER` is ascending. + SortBy ListCertificateBundleVersionsSortByEnum `mandatory:"false" contributesTo:"query" name:"sortBy" omitEmpty:"true"` + + // The sort order to use, either ascending (`ASC`) or descending (`DESC`). + SortOrder ListCertificateBundleVersionsSortOrderEnum `mandatory:"false" contributesTo:"query" name:"sortOrder" omitEmpty:"true"` + + // Metadata about the request. This information will not be transmitted to the service, but + // represents information that the SDK will consume to drive retry behavior. + RequestMetadata common.RequestMetadata +} + +func (request ListCertificateBundleVersionsRequest) String() string { + return common.PointerString(request) +} + +// HTTPRequest implements the OCIRequest interface +func (request ListCertificateBundleVersionsRequest) HTTPRequest(method, path string, binaryRequestBody *common.OCIReadSeekCloser, extraHeaders map[string]string) (http.Request, error) { + + _, err := request.ValidateEnumValue() + if err != nil { + return http.Request{}, err + } + return common.MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path, request, extraHeaders) +} + +// BinaryRequestBody implements the OCIRequest interface +func (request ListCertificateBundleVersionsRequest) BinaryRequestBody() (*common.OCIReadSeekCloser, bool) { + + return nil, false + +} + +// RetryPolicy implements the OCIRetryableRequest interface. This retrieves the specified retry policy. +func (request ListCertificateBundleVersionsRequest) RetryPolicy() *common.RetryPolicy { + return request.RequestMetadata.RetryPolicy +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (request ListCertificateBundleVersionsRequest) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingListCertificateBundleVersionsSortByEnum(string(request.SortBy)); !ok && request.SortBy != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for SortBy: %s. Supported values are: %s.", request.SortBy, strings.Join(GetListCertificateBundleVersionsSortByEnumStringValues(), ","))) + } + if _, ok := GetMappingListCertificateBundleVersionsSortOrderEnum(string(request.SortOrder)); !ok && request.SortOrder != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for SortOrder: %s. Supported values are: %s.", request.SortOrder, strings.Join(GetListCertificateBundleVersionsSortOrderEnumStringValues(), ","))) + } + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} + +// ListCertificateBundleVersionsResponse wrapper for the ListCertificateBundleVersions operation +type ListCertificateBundleVersionsResponse struct { + + // The underlying http response + RawResponse *http.Response + + // The CertificateBundleVersionCollection instance + CertificateBundleVersionCollection `presentIn:"body"` + + // Unique Oracle-assigned identifier for the request. If you need to contact Oracle about a particular request, please provide the request ID. + OpcRequestId *string `presentIn:"header" name:"opc-request-id"` +} + +func (response ListCertificateBundleVersionsResponse) String() string { + return common.PointerString(response) +} + +// HTTPResponse implements the OCIResponse interface +func (response ListCertificateBundleVersionsResponse) HTTPResponse() *http.Response { + return response.RawResponse +} + +// ListCertificateBundleVersionsSortByEnum Enum with underlying type: string +type ListCertificateBundleVersionsSortByEnum string + +// Set of constants representing the allowable values for ListCertificateBundleVersionsSortByEnum +const ( + ListCertificateBundleVersionsSortByVersionNumber ListCertificateBundleVersionsSortByEnum = "VERSION_NUMBER" +) + +var mappingListCertificateBundleVersionsSortByEnum = map[string]ListCertificateBundleVersionsSortByEnum{ + "VERSION_NUMBER": ListCertificateBundleVersionsSortByVersionNumber, +} + +var mappingListCertificateBundleVersionsSortByEnumLowerCase = map[string]ListCertificateBundleVersionsSortByEnum{ + "version_number": ListCertificateBundleVersionsSortByVersionNumber, +} + +// GetListCertificateBundleVersionsSortByEnumValues Enumerates the set of values for ListCertificateBundleVersionsSortByEnum +func GetListCertificateBundleVersionsSortByEnumValues() []ListCertificateBundleVersionsSortByEnum { + values := make([]ListCertificateBundleVersionsSortByEnum, 0) + for _, v := range mappingListCertificateBundleVersionsSortByEnum { + values = append(values, v) + } + return values +} + +// GetListCertificateBundleVersionsSortByEnumStringValues Enumerates the set of values in String for ListCertificateBundleVersionsSortByEnum +func GetListCertificateBundleVersionsSortByEnumStringValues() []string { + return []string{ + "VERSION_NUMBER", + } +} + +// GetMappingListCertificateBundleVersionsSortByEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingListCertificateBundleVersionsSortByEnum(val string) (ListCertificateBundleVersionsSortByEnum, bool) { + enum, ok := mappingListCertificateBundleVersionsSortByEnumLowerCase[strings.ToLower(val)] + return enum, ok +} + +// ListCertificateBundleVersionsSortOrderEnum Enum with underlying type: string +type ListCertificateBundleVersionsSortOrderEnum string + +// Set of constants representing the allowable values for ListCertificateBundleVersionsSortOrderEnum +const ( + ListCertificateBundleVersionsSortOrderAsc ListCertificateBundleVersionsSortOrderEnum = "ASC" + ListCertificateBundleVersionsSortOrderDesc ListCertificateBundleVersionsSortOrderEnum = "DESC" +) + +var mappingListCertificateBundleVersionsSortOrderEnum = map[string]ListCertificateBundleVersionsSortOrderEnum{ + "ASC": ListCertificateBundleVersionsSortOrderAsc, + "DESC": ListCertificateBundleVersionsSortOrderDesc, +} + +var mappingListCertificateBundleVersionsSortOrderEnumLowerCase = map[string]ListCertificateBundleVersionsSortOrderEnum{ + "asc": ListCertificateBundleVersionsSortOrderAsc, + "desc": ListCertificateBundleVersionsSortOrderDesc, +} + +// GetListCertificateBundleVersionsSortOrderEnumValues Enumerates the set of values for ListCertificateBundleVersionsSortOrderEnum +func GetListCertificateBundleVersionsSortOrderEnumValues() []ListCertificateBundleVersionsSortOrderEnum { + values := make([]ListCertificateBundleVersionsSortOrderEnum, 0) + for _, v := range mappingListCertificateBundleVersionsSortOrderEnum { + values = append(values, v) + } + return values +} + +// GetListCertificateBundleVersionsSortOrderEnumStringValues Enumerates the set of values in String for ListCertificateBundleVersionsSortOrderEnum +func GetListCertificateBundleVersionsSortOrderEnumStringValues() []string { + return []string{ + "ASC", + "DESC", + } +} + +// GetMappingListCertificateBundleVersionsSortOrderEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingListCertificateBundleVersionsSortOrderEnum(val string) (ListCertificateBundleVersionsSortOrderEnum, bool) { + enum, ok := mappingListCertificateBundleVersionsSortOrderEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/revocation_reason.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/revocation_reason.go new file mode 100644 index 00000000000..9f05582dbce --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/revocation_reason.go @@ -0,0 +1,80 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "strings" +) + +// RevocationReasonEnum Enum with underlying type: string +type RevocationReasonEnum string + +// Set of constants representing the allowable values for RevocationReasonEnum +const ( + RevocationReasonUnspecified RevocationReasonEnum = "UNSPECIFIED" + RevocationReasonKeyCompromise RevocationReasonEnum = "KEY_COMPROMISE" + RevocationReasonCaCompromise RevocationReasonEnum = "CA_COMPROMISE" + RevocationReasonAffiliationChanged RevocationReasonEnum = "AFFILIATION_CHANGED" + RevocationReasonSuperseded RevocationReasonEnum = "SUPERSEDED" + RevocationReasonCessationOfOperation RevocationReasonEnum = "CESSATION_OF_OPERATION" + RevocationReasonPrivilegeWithdrawn RevocationReasonEnum = "PRIVILEGE_WITHDRAWN" + RevocationReasonAaCompromise RevocationReasonEnum = "AA_COMPROMISE" +) + +var mappingRevocationReasonEnum = map[string]RevocationReasonEnum{ + "UNSPECIFIED": RevocationReasonUnspecified, + "KEY_COMPROMISE": RevocationReasonKeyCompromise, + "CA_COMPROMISE": RevocationReasonCaCompromise, + "AFFILIATION_CHANGED": RevocationReasonAffiliationChanged, + "SUPERSEDED": RevocationReasonSuperseded, + "CESSATION_OF_OPERATION": RevocationReasonCessationOfOperation, + "PRIVILEGE_WITHDRAWN": RevocationReasonPrivilegeWithdrawn, + "AA_COMPROMISE": RevocationReasonAaCompromise, +} + +var mappingRevocationReasonEnumLowerCase = map[string]RevocationReasonEnum{ + "unspecified": RevocationReasonUnspecified, + "key_compromise": RevocationReasonKeyCompromise, + "ca_compromise": RevocationReasonCaCompromise, + "affiliation_changed": RevocationReasonAffiliationChanged, + "superseded": RevocationReasonSuperseded, + "cessation_of_operation": RevocationReasonCessationOfOperation, + "privilege_withdrawn": RevocationReasonPrivilegeWithdrawn, + "aa_compromise": RevocationReasonAaCompromise, +} + +// GetRevocationReasonEnumValues Enumerates the set of values for RevocationReasonEnum +func GetRevocationReasonEnumValues() []RevocationReasonEnum { + values := make([]RevocationReasonEnum, 0) + for _, v := range mappingRevocationReasonEnum { + values = append(values, v) + } + return values +} + +// GetRevocationReasonEnumStringValues Enumerates the set of values in String for RevocationReasonEnum +func GetRevocationReasonEnumStringValues() []string { + return []string{ + "UNSPECIFIED", + "KEY_COMPROMISE", + "CA_COMPROMISE", + "AFFILIATION_CHANGED", + "SUPERSEDED", + "CESSATION_OF_OPERATION", + "PRIVILEGE_WITHDRAWN", + "AA_COMPROMISE", + } +} + +// GetMappingRevocationReasonEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingRevocationReasonEnum(val string) (RevocationReasonEnum, bool) { + enum, ok := mappingRevocationReasonEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/revocation_status.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/revocation_status.go new file mode 100644 index 00000000000..606b6c879ff --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/revocation_status.go @@ -0,0 +1,45 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// RevocationStatus The current revocation status of the certificate or certificate authority (CA). +type RevocationStatus struct { + + // The time when the certificate or CA was revoked. + TimeRevoked *common.SDKTime `mandatory:"true" json:"timeRevoked"` + + // The reason that the certificate or CA was revoked. + RevocationReason RevocationReasonEnum `mandatory:"true" json:"revocationReason"` +} + +func (m RevocationStatus) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m RevocationStatus) ValidateEnumValue() (bool, error) { + errMessage := []string{} + if _, ok := GetMappingRevocationReasonEnum(string(m.RevocationReason)); !ok && m.RevocationReason != "" { + errMessage = append(errMessage, fmt.Sprintf("unsupported enum value for RevocationReason: %s. Supported values are: %s.", m.RevocationReason, strings.Join(GetRevocationReasonEnumStringValues(), ","))) + } + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/validity.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/validity.go new file mode 100644 index 00000000000..924b566c742 --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/validity.go @@ -0,0 +1,44 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "fmt" + "github.com/oracle/oci-go-sdk/v65/common" + "strings" +) + +// Validity An object that describes a period of time during which an entity is valid. +type Validity struct { + + // The date on which the certificate validity period begins, expressed in RFC 3339 (https://tools.ietf.org/html/rfc3339) timestamp format. + // Example: `2019-04-03T21:10:29.600Z` + TimeOfValidityNotBefore *common.SDKTime `mandatory:"true" json:"timeOfValidityNotBefore"` + + // The date on which the certificate validity period ends, expressed in RFC 3339 (https://tools.ietf.org/html/rfc3339) timestamp format. + // Example: `2019-04-03T21:10:29.600Z` + TimeOfValidityNotAfter *common.SDKTime `mandatory:"true" json:"timeOfValidityNotAfter"` +} + +func (m Validity) String() string { + return common.PointerString(m) +} + +// ValidateEnumValue returns an error when providing an unsupported enum value +// This function is being called during constructing API request process +// Not recommended for calling this function directly +func (m Validity) ValidateEnumValue() (bool, error) { + errMessage := []string{} + + if len(errMessage) > 0 { + return true, fmt.Errorf(strings.Join(errMessage, "\n")) + } + return false, nil +} diff --git a/vendor/github.com/oracle/oci-go-sdk/v65/certificates/version_stage.go b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/version_stage.go new file mode 100644 index 00000000000..d1428d0473e --- /dev/null +++ b/vendor/github.com/oracle/oci-go-sdk/v65/certificates/version_stage.go @@ -0,0 +1,72 @@ +// Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved. +// This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license. +// Code generated. DO NOT EDIT. + +// Certificates Service Retrieval API +// +// API for retrieving certificates. +// + +package certificates + +import ( + "strings" +) + +// VersionStageEnum Enum with underlying type: string +type VersionStageEnum string + +// Set of constants representing the allowable values for VersionStageEnum +const ( + VersionStageCurrent VersionStageEnum = "CURRENT" + VersionStagePending VersionStageEnum = "PENDING" + VersionStageLatest VersionStageEnum = "LATEST" + VersionStagePrevious VersionStageEnum = "PREVIOUS" + VersionStageDeprecated VersionStageEnum = "DEPRECATED" + VersionStageFailed VersionStageEnum = "FAILED" +) + +var mappingVersionStageEnum = map[string]VersionStageEnum{ + "CURRENT": VersionStageCurrent, + "PENDING": VersionStagePending, + "LATEST": VersionStageLatest, + "PREVIOUS": VersionStagePrevious, + "DEPRECATED": VersionStageDeprecated, + "FAILED": VersionStageFailed, +} + +var mappingVersionStageEnumLowerCase = map[string]VersionStageEnum{ + "current": VersionStageCurrent, + "pending": VersionStagePending, + "latest": VersionStageLatest, + "previous": VersionStagePrevious, + "deprecated": VersionStageDeprecated, + "failed": VersionStageFailed, +} + +// GetVersionStageEnumValues Enumerates the set of values for VersionStageEnum +func GetVersionStageEnumValues() []VersionStageEnum { + values := make([]VersionStageEnum, 0) + for _, v := range mappingVersionStageEnum { + values = append(values, v) + } + return values +} + +// GetVersionStageEnumStringValues Enumerates the set of values in String for VersionStageEnum +func GetVersionStageEnumStringValues() []string { + return []string{ + "CURRENT", + "PENDING", + "LATEST", + "PREVIOUS", + "DEPRECATED", + "FAILED", + } +} + +// GetMappingVersionStageEnum performs case Insensitive comparison on enum value and return the desired enum +func GetMappingVersionStageEnum(val string) (VersionStageEnum, bool) { + enum, ok := mappingVersionStageEnumLowerCase[strings.ToLower(val)] + return enum, ok +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 008e4a8dca1..708aa49be28 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -222,7 +222,9 @@ github.com/hashicorp/terraform-plugin-mux/tf5muxserver ## explicit; go 1.22.0 github.com/hashicorp/terraform-plugin-sdk/v2/diag github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff +github.com/hashicorp/terraform-plugin-sdk/v2/helper/id github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging +github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure @@ -234,6 +236,7 @@ github.com/hashicorp/terraform-plugin-sdk/v2/internal/helper/hashcode github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging github.com/hashicorp/terraform-plugin-sdk/v2/internal/plans/objchange github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugin/convert +github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest github.com/hashicorp/terraform-plugin-sdk/v2/internal/tfdiags github.com/hashicorp/terraform-plugin-sdk/v2/meta github.com/hashicorp/terraform-plugin-sdk/v2/plugin @@ -312,6 +315,7 @@ github.com/oracle/oci-go-sdk/v65/bds github.com/oracle/oci-go-sdk/v65/blockchain github.com/oracle/oci-go-sdk/v65/budget github.com/oracle/oci-go-sdk/v65/capacitymanagement +github.com/oracle/oci-go-sdk/v65/certificates github.com/oracle/oci-go-sdk/v65/certificatesmanagement github.com/oracle/oci-go-sdk/v65/cloudbridge github.com/oracle/oci-go-sdk/v65/cloudguard diff --git a/website/docs/d/certificates_certificate_authority_bundle.html.markdown b/website/docs/d/certificates_certificate_authority_bundle.html.markdown new file mode 100644 index 00000000000..01b5d2a81a4 --- /dev/null +++ b/website/docs/d/certificates_certificate_authority_bundle.html.markdown @@ -0,0 +1,71 @@ +--- +subcategory: "Certificates" +layout: "oci" +page_title: "Oracle Cloud Infrastructure: oci_certificates_certificate_authority_bundle" +sidebar_current: "docs-oci-datasource-certificates-certificate_authority_bundle" +description: |- +Provides details about a certificate authority bundle in Oracle Cloud Infrastructure Certificates Retrieval service +--- + +# Data Source: oci_certificates_certificate_bundle +This data source provides details about a specific certificate authority bundle in Oracle Cloud Infrastructure Certificates Retrieval service. + +Gets details about the specified certificate authority bundle. + +## Example Usage + +```hcl +data "oci_certificates_certificate_authority_bundle" "test_certificate_authority_bundle" { + #Required + certificate_authority_id = oci_certificates_management_certificate_authority.test_certificate_authority.id + + #Optional + certificate_version_name = oci_certificates_management_certificate_authority.test_certificate_authority.current_version.version_name + stage = "CURRENT" + version_number = oci_certificates_management_certificate_authority.test_certificate_authority.current_version.version_number +} +``` + +## Argument Reference + +The following arguments are supported: + +* `certificate_authority_id` - (Required) The OCID of the certificate authority (CA). +* `certificate_version_name` - (Optional) The name of the certificate authority (CA). (This might be referred to as the +name of the CA version, as every CA consists of at least one version.) Names are unique across versions of a given CA. +* `stage` - (Optional) The rotation state of the certificate authority version. Valid values are: `CURRENT`, `PENDING`, +`LATEST`, `PREVIOUS` or `DEPRECATED`. +* `version_number` - (Optional) The version number of the certificate authority (CA). + +## Attributes Reference + +The following attributes are exported: + +* `cert_chain_pem` - The certificate chain (in PEM format) for this CA version. +* `certificate_authority_id` - The OCID of the certificate authority (CA). +* `certificate_authority_name` - The name of the CA. +* `certificate_pem` - The certificate (in PEM format) for this CA version. +* `revocation_status` - The revocation status of the certificate. +* `serial_number` - A unique certificate identifier used in certificate revocation tracking, formatted as octets. +* `stages` - A list of rotation states for this CA. +* `time_created` - An optional property indicating when the certificate version was created, expressed in RFC 3339 +timestamp format. +* `validity` - The validity of the certificate. +* `version_name` - The name of the CA version. +* `version_number` - The version number of the CA. + +### Revocation Status Reference + +The following attributes are exported: + +* `revocation_reason` - The reason that the CA was revoked. +* `time_revoked` - The time when the CA was revoked. + +### Validity Reference + +The following attributes are exported: + +* `time_of_validity_not_after` - The date on which the CA validity period ends, expressed in RFC 3339 timestamp +format. +* `time_of_validity_not_before` - The date on which the CA validity period begins, expressed in RFC 3339 +timestamp format. diff --git a/website/docs/d/certificates_certificate_bundle.html.markdown b/website/docs/d/certificates_certificate_bundle.html.markdown new file mode 100644 index 00000000000..b0d0a5e1805 --- /dev/null +++ b/website/docs/d/certificates_certificate_bundle.html.markdown @@ -0,0 +1,82 @@ +--- +subcategory: "Certificates" +layout: "oci" +page_title: "Oracle Cloud Infrastructure: oci_certificates_certificate_bundle" +sidebar_current: "docs-oci-datasource-certificates-certificate_bundle" +description: |- +Provides details about a certificate bundle in Oracle Cloud Infrastructure Certificates Retrieval service +--- + +# Data Source: oci_certificates_certificate_bundle +This data source provides details about a specific certificate bundle in Oracle Cloud Infrastructure Certificates Retrieval service. + +Gets details about the specified certificate bundle. + +## Example Usage + +```hcl +data "oci_certificates_certificate_bundle" "test_certificate_bundle" { + #Required + certificate_id = oci_certificates_management_certificate.test_certificate.id + + #Optional + certificate_bundle_type = "CERTIFICATE_CONTENT_WITH_PRIVATE_KEY" + certificate_version_name = oci_certificates_management_certificate.test_certificate.current_version.version_name + stage = "CURRENT" + version_number = oci_certificates_management_certificate.test_certificate.current_version.version_number +} +``` + +## Argument Reference + +The following arguments are supported: + +* `certificate_id` - (Required) The OCID of the certificate. +* `certificate_bundle_type` - (Optional) The type of certificate bundle. By default, the private key fields are not +returned. When querying for certificate bundles, to return results with certificate contents, the private key in PEM +format, and the private key passphrase, specify the value of this parameter as CERTIFICATE_CONTENT_WITH_PRIVATE_KEY. +Valid values are: `CERTIFICATE_CONTENT_PUBLIC_ONLY` or `CERTIFICATE_CONTENT_WITH_PRIVATE_KEY`. +* `certificate_version_name` - (Optional) The name of the certificate. (This might be referred to as the name of the +certificate version, as every certificate consists of at least one version.) Names are unique across versions of a +given certificate. +* `stage` - (Optional) The rotation state of the certificate version. Valid values are: `CURRENT`, `PENDING`, `LATEST`, +`PREVIOUS` or `DEPRECATED`. +* `version_number` - (Optional) The version number of the certificate. + +## Attributes Reference + +The following attributes are exported: + +* `cert_chain_pem` - The certificate chain (in PEM format) for the certificate bundle. +* `certificate_bundle_type` - The type of certificate bundle, which indicates whether the private key fields are included. +* `certificate_id` - The OCID of the certificate. +* `certificate_name` - The name of the certificate. +* `certificate_pem` - The certificate (in PEM format) for the certificate bundle. +* `private_key_pem` - The private key (in PEM format) for the certificate. This is only set if `certificate_bundle_type` +is set to `CERTIFICATE_CONTENT_WITH_PRIVATE_KEY`. +* `private_key_pem_passphrase` - The passphrase for the private key. This is only set if `certificate_bundle_type` +is set to `CERTIFICATE_CONTENT_WITH_PRIVATE_KEY`. +* `revocation_status` - The revocation status of the certificate. +* `serial_number` - A unique certificate identifier used in certificate revocation tracking, formatted as octets. +* `stages` - A list of rotation states for the certificate bundle. +* `time_created` - An optional property indicating when the certificate version was created, expressed in RFC 3339 +timestamp format. +* `validity` - The validity of the certificate. +* `version_name` - The name of the certificate version. +* `version_number` - The version number of the certificate. + +### Revocation Status Reference + +The following attributes are exported: + +* `revocation_reason` - The reason that the certificate was revoked. +* `time_revoked` - The time when the certificate was revoked. + +### Validity Reference + +The following attributes are exported: + +* `time_of_validity_not_after` - The date on which the certificate validity period ends, expressed in RFC 3339 timestamp +format. +* `time_of_validity_not_before` - The date on which the certificate validity period begins, expressed in RFC 3339 +timestamp format.