From 0e998509b72b8dae1f20741b048517db40ee7743 Mon Sep 17 00:00:00 2001 From: skpratt Date: Fri, 9 Feb 2024 11:03:52 -0600 Subject: [PATCH 1/5] add v2 exported service config resources --- ...onsul_config_entry_v2_exported_services.go | 134 ++++++++++++ ..._config_entry_v2_exported_services_test.go | 87 ++++++++ ...onsul_config_entry_v2_exported_services.go | 206 ++++++++++++++++++ ..._config_entry_v2_exported_services_test.go | 88 ++++++++ consul/resource_provider.go | 106 ++++----- go.mod | 12 +- go.sum | 22 +- 7 files changed, 591 insertions(+), 64 deletions(-) create mode 100644 consul/data_source_consul_config_entry_v2_exported_services.go create mode 100644 consul/data_source_consul_config_entry_v2_exported_services_test.go create mode 100644 consul/resource_consul_config_entry_v2_exported_services.go create mode 100644 consul/resource_consul_config_entry_v2_exported_services_test.go diff --git a/consul/data_source_consul_config_entry_v2_exported_services.go b/consul/data_source_consul_config_entry_v2_exported_services.go new file mode 100644 index 00000000..0bc211c1 --- /dev/null +++ b/consul/data_source_consul_config_entry_v2_exported_services.go @@ -0,0 +1,134 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package consul + +import ( + "encoding/json" + "fmt" + + "github.com/hashicorp/consul/api" + pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "google.golang.org/protobuf/encoding/protojson" +) + +func dataSourceConsulConfigEntryV2ExportedServices() *schema.Resource { + return &schema.Resource{ + Read: dataSourceConsulV2ExportedServicesRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the config entry to read.", + }, + + "kind": { + Type: schema.TypeString, + Required: true, + Description: "The kind of exported services config (ExportedServices, NamespaceExportedServices, PartitionExportedServices).", + }, + + "partition": { + Type: schema.TypeString, + Optional: true, + Description: "The partition the config entry is associated with.", + }, + + "namespace": { + Type: schema.TypeString, + Optional: true, + Description: "The namespace the config entry is associated with.", + }, + + "services": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "The exported services.", + }, + + "partition_consumers": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "The exported service partition consumers.", + }, + "peer_consumers": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "The exported service peer consumers.", + }, + "sameness_group_consumers": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "The exported service sameness group consumers.", + }, + }, + } +} + +func dataSourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interface{}) error { + client, qOpts, _ := getClient(d, meta) + name := d.Get("name").(string) + kind := d.Get("kind").(string) + gvk := &api.GVK{ + Group: "multicluster", + Version: "v2", + Kind: kind, + } + resp, err := client.Resource().Read(gvk, name, qOpts) + if err != nil || resp == nil { + return fmt.Errorf("exported services config not found: %s", name) + } + respData, err := json.Marshal(resp["data"]) + if err != nil { + return fmt.Errorf("failed to unmarshal response data: %v", err) + } + data := &pbmulticluster.ExportedServices{} + if err = protojson.Unmarshal(respData, data); err != nil { + return fmt.Errorf("failed to unmarshal to proto message: %v", err) + } + respID, err := json.Marshal(resp["id"]) + if err != nil { + return fmt.Errorf("failed to unmarshal response id: %v", err) + } + id := &pbresource.ID{} + if err = protojson.Unmarshal(respID, id); err != nil { + return fmt.Errorf("Failed to unmarshal to proto message: %v", err) + } + var partitions []string + var peers []string + var samenessgroups []string + for _, e := range data.Consumers { + switch v := e.ConsumerTenancy.(type) { + case *pbmulticluster.ExportedServicesConsumer_Peer: + peers = append(peers, v.Peer) + case *pbmulticluster.ExportedServicesConsumer_Partition: + partitions = append(partitions, v.Partition) + case *pbmulticluster.ExportedServicesConsumer_SamenessGroup: + samenessgroups = append(samenessgroups, v.SamenessGroup) + default: + return fmt.Errorf("unknown exported service consumer type: %T", v) + } + } + d.SetId(id.Uid) + sw := newStateWriter(d) + sw.set("services", data.Services) + sw.set("partition_consumers", partitions) + sw.set("peer_consumers", peers) + sw.set("sameness_group_consumers", samenessgroups) + return sw.error() +} diff --git a/consul/data_source_consul_config_entry_v2_exported_services_test.go b/consul/data_source_consul_config_entry_v2_exported_services_test.go new file mode 100644 index 00000000..e6e7124a --- /dev/null +++ b/consul/data_source_consul_config_entry_v2_exported_services_test.go @@ -0,0 +1,87 @@ +package consul + +import ( + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccDataExportedServicesV2_basic(t *testing.T) { + providers, _ := startTestServer(t) + + resource.Test(t, resource.TestCase{ + Providers: providers, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceExportedServicesV2ConfigNotFound, + ExpectError: regexp.MustCompile(`exported services config not found: not-found`), + }, + { + Config: testAccDataSourceExportedServicesV2ConfigBasic, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "name", "test"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "kind", "ExportedServices"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "namespace", "default"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "partition", "default"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "services.0", "s1"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "sameness_group_consumers.0", "sg1"), + ), + }, + { + Config: testAccDataSourceComputedExportedServicesV2ConfigBasic, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "name", "default"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "kind", "ComputedExportedServices"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "partition", "default"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "services.0", "s1"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "sameness_group_consumers.0", "sg1"), + ), + }, + }, + }) +} + +const testAccDataSourceComputedExportedServicesV2ConfigBasic = ` +resource "consul_config_entry_v2_exported_services" "test" { + name = "test" + kind = "ExportedServices" + namespace = "default" + partition = "default" + services = ["s1"] + partition_consumers = ["default"] +} + +data "consul_config_entry_v2_exported_services" "read" { + name = "default" + kind = "ComputedExportedServices" + partition = "default" +} +` + +const testAccDataSourceExportedServicesV2ConfigBasic = ` +resource "consul_config_entry_v2_exported_services" "test" { + name = "test" + kind = "ExportedServices" + namespace = "default" + partition = "default" + services = ["s1"] + sameness_group_consumers = ["sg1"] +} + +data "consul_config_entry_v2_exported_services" "read" { + name = consul_config_entry_v2_exported_services.test.name + kind = consul_config_entry_v2_exported_services.test.kind + namespace = consul_config_entry_v2_exported_services.test.namespace + partition = consul_config_entry_v2_exported_services.test.partition +} +` + +const testAccDataSourceExportedServicesV2ConfigNotFound = ` +data "consul_config_entry_v2_exported_services" "test" { + name = "not-found" + kind = "ExportedServices" + namespace = "default" + partition = "default" +} +` diff --git a/consul/resource_consul_config_entry_v2_exported_services.go b/consul/resource_consul_config_entry_v2_exported_services.go new file mode 100644 index 00000000..9ad4bf34 --- /dev/null +++ b/consul/resource_consul_config_entry_v2_exported_services.go @@ -0,0 +1,206 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package consul + +import ( + "encoding/json" + "fmt" + + "github.com/hashicorp/consul/api" + pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "google.golang.org/protobuf/encoding/protojson" +) + +func resourceConsulV2ExportedServices() *schema.Resource { + return &schema.Resource{ + Create: resourceConsulV2ExportedServicesCreate, + Update: resourceConsulV2ExportedServicesUpdate, + Read: resourceConsulV2ExportedServicesRead, + Delete: resourceConsulV2ExportedServicesDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the config entry to read.", + }, + + "kind": { + Type: schema.TypeString, + Required: true, + Description: "The kind of exported services config (ExportedServices, NamespaceExportedServices, PartitionExportedServices).", + }, + + "partition": { + Type: schema.TypeString, + Required: true, + Description: "The partition the config entry is associated with.", + ForceNew: true, + }, + + "namespace": { + Type: schema.TypeString, + Optional: true, + Description: "The namespace the config entry is associated with.", + ForceNew: true, + }, + + "services": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "The exported services.", + }, + + "partition_consumers": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "The exported service partition consumers.", + }, + "peer_consumers": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "The exported service peer consumers.", + }, + "sameness_group_consumers": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "The exported service sameness group consumers.", + }, + }, + } +} + +func resourceConsulV2ExportedServicesCreate(d *schema.ResourceData, meta interface{}) error { + return resourceConsulV2ExportedServicesUpdate(d, meta) +} + +func resourceConsulV2ExportedServicesUpdate(d *schema.ResourceData, meta interface{}) error { + client, qOpts, _ := getClient(d, meta) + name := d.Get("name").(string) + kind := d.Get("kind").(string) + gvk := &api.GVK{ + Group: "multicluster", + Version: "v2", + Kind: kind, + } + var consumers []map[string]any + peerConsumers := d.Get("peer_consumers").([]interface{}) + for _, p := range peerConsumers { + consumers = append(consumers, map[string]any{"peer": p}) + } + partitionConsumers := d.Get("partition_consumers").([]interface{}) + for _, ap := range partitionConsumers { + consumers = append(consumers, map[string]any{"partition": ap}) + } + samenessConsumers := d.Get("sameness_group_consumers").([]interface{}) + for _, ap := range samenessConsumers { + consumers = append(consumers, map[string]any{"sameness_group": ap}) + } + data := map[string]any{"consumers": consumers} + services := d.Get("services").([]interface{}) + if len(services) > 0 { + data["services"] = services + } + wReq := &api.WriteRequest{ + Metadata: nil, + Data: data, + Owner: nil, + } + resp, _, err := client.Resource().Apply(gvk, name, qOpts, wReq) + if err != nil || resp == nil { + return fmt.Errorf("failed to write exported services config '%s': %v", name, err) + } + d.SetId(resp.ID.Type.Kind + resp.ID.Tenancy.Partition + resp.ID.Tenancy.Namespace + resp.ID.Name) + sw := newStateWriter(d) + sw.set("name", resp.ID.Name) + sw.set("kind", resp.ID.Type.Kind) + sw.set("partition", resp.ID.Tenancy.Partition) + sw.set("namespace", resp.ID.Tenancy.Namespace) + return resourceConsulV2ExportedServicesRead(d, meta) +} + +func resourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interface{}) error { + client, qOpts, _ := getClient(d, meta) + name := d.Get("name").(string) + kind := d.Get("kind").(string) + gvk := &api.GVK{ + Group: "multicluster", + Version: "v2", + Kind: kind, + } + resp, err := client.Resource().Read(gvk, name, qOpts) + if err != nil || resp == nil { + return fmt.Errorf("exported services config not found: %s", name) + } + respData, err := json.Marshal(resp["data"]) + if err != nil { + return fmt.Errorf("failed to unmarshal response data: %v", err) + } + data := &pbmulticluster.ExportedServices{} + if err = protojson.Unmarshal(respData, data); err != nil { + return fmt.Errorf("failed to unmarshal to proto message: %v", err) + } + respID, err := json.Marshal(resp["id"]) + if err != nil { + return fmt.Errorf("failed to unmarshal response id: %v", err) + } + id := &pbresource.ID{} + if err = protojson.Unmarshal(respID, id); err != nil { + return fmt.Errorf("Failed to unmarshal to proto message: %v", err) + } + var partitions []string + var peers []string + var samenessgroups []string + for _, e := range data.Consumers { + switch v := e.ConsumerTenancy.(type) { + case *pbmulticluster.ExportedServicesConsumer_Peer: + peers = append(peers, v.Peer) + case *pbmulticluster.ExportedServicesConsumer_Partition: + partitions = append(partitions, v.Partition) + case *pbmulticluster.ExportedServicesConsumer_SamenessGroup: + samenessgroups = append(samenessgroups, v.SamenessGroup) + default: + return fmt.Errorf("unknown exported service consumer type: %T", v) + } + } + sw := newStateWriter(d) + sw.set("services", data.Services) + sw.set("name", id.Name) + sw.set("kind", id.Type.Kind) + sw.set("partition", id.Tenancy.Partition) + sw.set("namespace", id.Tenancy.Namespace) + sw.set("partition_consumers", partitions) + sw.set("peer_consumers", peers) + sw.set("sameness_group_consumers", samenessgroups) + return sw.error() +} + +func resourceConsulV2ExportedServicesDelete(d *schema.ResourceData, meta interface{}) error { + client, qOpts, _ := getClient(d, meta) + gvk := &api.GVK{ + Group: "multicluster", + Version: "v2", + Kind: "ExportedServices", + } + name := d.Get("name").(string) + return client.Resource().Delete(gvk, name, qOpts) +} diff --git a/consul/resource_consul_config_entry_v2_exported_services_test.go b/consul/resource_consul_config_entry_v2_exported_services_test.go new file mode 100644 index 00000000..ddfe4ad2 --- /dev/null +++ b/consul/resource_consul_config_entry_v2_exported_services_test.go @@ -0,0 +1,88 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package consul + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccConsulExportedServicesV2_basic(t *testing.T) { + providers, _ := startTestServer(t) + + resource.Test(t, resource.TestCase{ + Providers: providers, + Steps: []resource.TestStep{ + { + Config: testAccConsulExportedServicesV2Basic, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.test", "name", "test"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.test", "kind", "ExportedServices"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.test", "partition", "default"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.test", "services.#", "2"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.test", "services.0", "s1"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.test", "services.1", "s2"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.test", "sameness_group_consumers.#", "1"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.test", "sameness_group_consumers.0", "sg1"), + ), + }, + { + Config: testAccConsulNamespaceExportedServicesV2Basic, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.nstest", "name", "nstest"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.nstest", "kind", "NamespaceExportedServices"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.nstest", "partition", "default"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.nstest", "peer_consumers.#", "1"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.nstest", "peer_consumers.0", "p1"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.nstest", "partition_consumers.#", "2"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.nstest", "partition_consumers.0", "ap1"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.nstest", "partition_consumers.1", "ap2"), + ), + }, + { + Config: testAccConsulPartitionExportedServicesV2Basic, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.ptest", "name", "ptest"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.ptest", "kind", "PartitionExportedServices"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.ptest", "partition", "default"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.ptest", "peer_consumers.#", "1"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.ptest", "peer_consumers.0", "p1"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.ptest", "partition_consumers.#", "2"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.ptest", "partition_consumers.0", "ap1"), + resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.ptest", "partition_consumers.1", "ap2"), + ), + }, + }, + }) +} + +const testAccConsulExportedServicesV2Basic = ` +resource "consul_config_entry_v2_exported_services" "test" { + name = "test" + kind = "ExportedServices" + namespace = "default" + partition = "default" + services = ["s1", "s2"] + sameness_group_consumers = ["sg1"] +}` + +const testAccConsulNamespaceExportedServicesV2Basic = ` +resource "consul_config_entry_v2_exported_services" "nstest" { + name = "nstest" + kind = "NamespaceExportedServices" + namespace = "default" + partition = "default" + peer_consumers = ["p1"] + partition_consumers = ["ap1", "ap2"] +}` + +const testAccConsulPartitionExportedServicesV2Basic = ` +resource "consul_config_entry_v2_exported_services" "ptest" { + name = "ptest" + kind = "PartitionExportedServices" + partition = "default" + peer_consumers = ["p1"] + partition_consumers = ["ap1", "ap2"] +}` diff --git a/consul/resource_provider.go b/consul/resource_provider.go index 5b757876..41782415 100644 --- a/consul/resource_provider.go +++ b/consul/resource_provider.go @@ -196,26 +196,27 @@ func Provider() terraform.ResourceProvider { }, DataSourcesMap: map[string]*schema.Resource{ - "consul_agent_self": dataSourceConsulAgentSelf(), - "consul_agent_config": dataSourceConsulAgentConfig(), - "consul_autopilot_health": dataSourceConsulAutopilotHealth(), - "consul_nodes": dataSourceConsulNodes(), - "consul_service": dataSourceConsulService(), - "consul_service_health": dataSourceConsulServiceHealth(), - "consul_services": dataSourceConsulServices(), - "consul_keys": dataSourceConsulKeys(), - "consul_key_prefix": dataSourceConsulKeyPrefix(), - "consul_acl_auth_method": dataSourceConsulACLAuthMethod(), - "consul_acl_policy": dataSourceConsulACLPolicy(), - "consul_acl_role": dataSourceConsulACLRole(), - "consul_acl_token": dataSourceConsulACLToken(), - "consul_acl_token_secret_id": dataSourceConsulACLTokenSecretID(), - "consul_network_segments": dataSourceConsulNetworkSegments(), - "consul_network_area_members": dataSourceConsulNetworkAreaMembers(), - "consul_datacenters": dataSourceConsulDatacenters(), - "consul_config_entry": dataSourceConsulConfigEntry(), - "consul_peering": dataSourceConsulPeering(), - "consul_peerings": dataSourceConsulPeerings(), + "consul_agent_self": dataSourceConsulAgentSelf(), + "consul_agent_config": dataSourceConsulAgentConfig(), + "consul_autopilot_health": dataSourceConsulAutopilotHealth(), + "consul_nodes": dataSourceConsulNodes(), + "consul_service": dataSourceConsulService(), + "consul_service_health": dataSourceConsulServiceHealth(), + "consul_services": dataSourceConsulServices(), + "consul_keys": dataSourceConsulKeys(), + "consul_key_prefix": dataSourceConsulKeyPrefix(), + "consul_acl_auth_method": dataSourceConsulACLAuthMethod(), + "consul_acl_policy": dataSourceConsulACLPolicy(), + "consul_acl_role": dataSourceConsulACLRole(), + "consul_acl_token": dataSourceConsulACLToken(), + "consul_acl_token_secret_id": dataSourceConsulACLTokenSecretID(), + "consul_network_segments": dataSourceConsulNetworkSegments(), + "consul_network_area_members": dataSourceConsulNetworkAreaMembers(), + "consul_datacenters": dataSourceConsulDatacenters(), + "consul_config_entry": dataSourceConsulConfigEntry(), + "consul_config_entry_v2_exported_services": dataSourceConsulConfigEntryV2ExportedServices(), + "consul_peering": dataSourceConsulPeering(), + "consul_peerings": dataSourceConsulPeerings(), // Aliases to limit the impact of rename of catalog // datasources @@ -225,38 +226,39 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "consul_acl_auth_method": resourceConsulACLAuthMethod(), - "consul_acl_binding_rule": resourceConsulACLBindingRule(), - "consul_acl_policy": resourceConsulACLPolicy(), - "consul_acl_role_policy_attachment": resourceConsulACLRolePolicyAttachment(), - "consul_acl_role": resourceConsulACLRole(), - "consul_acl_token_policy_attachment": resourceConsulACLTokenPolicyAttachment(), - "consul_acl_token_role_attachment": resourceConsulACLTokenRoleAttachment(), - "consul_acl_token": resourceConsulACLToken(), - "consul_admin_partition": resourceConsulAdminPartition(), - "consul_agent_service": resourceConsulAgentService(), - "consul_autopilot_config": resourceConsulAutopilotConfig(), - "consul_catalog_entry": resourceConsulCatalogEntry(), - "consul_certificate_authority": resourceConsulCertificateAuthority(), - "consul_config_entry_service_defaults": resourceFromConfigEntryImplementation(&serviceDefaults{}), - "consul_config_entry_service_intentions": resourceFromConfigEntryImplementation(&serviceIntentions{}), - "consul_config_entry_service_resolver": resourceFromConfigEntryImplementation(&serviceResolver{}), - "consul_config_entry_service_router": resourceFromConfigEntryImplementation(&serviceRouter{}), - "consul_config_entry_service_splitter": resourceFromConfigEntryImplementation(&serviceSplitter{}), - "consul_config_entry": resourceConsulConfigEntry(), - "consul_intention": resourceConsulIntention(), - "consul_key_prefix": resourceConsulKeyPrefix(), - "consul_keys": resourceConsulKeys(), - "consul_license": resourceConsulLicense(), - "consul_namespace_policy_attachment": resourceConsulNamespacePolicyAttachment(), - "consul_namespace_role_attachment": resourceConsulNamespaceRoleAttachment(), - "consul_namespace": resourceConsulNamespace(), - "consul_network_area": resourceConsulNetworkArea(), - "consul_node": resourceConsulNode(), - "consul_peering_token": resourceSourceConsulPeeringToken(), - "consul_peering": resourceSourceConsulPeering(), - "consul_prepared_query": resourceConsulPreparedQuery(), - "consul_service": resourceConsulService(), + "consul_acl_auth_method": resourceConsulACLAuthMethod(), + "consul_acl_binding_rule": resourceConsulACLBindingRule(), + "consul_acl_policy": resourceConsulACLPolicy(), + "consul_acl_role_policy_attachment": resourceConsulACLRolePolicyAttachment(), + "consul_acl_role": resourceConsulACLRole(), + "consul_acl_token_policy_attachment": resourceConsulACLTokenPolicyAttachment(), + "consul_acl_token_role_attachment": resourceConsulACLTokenRoleAttachment(), + "consul_acl_token": resourceConsulACLToken(), + "consul_admin_partition": resourceConsulAdminPartition(), + "consul_agent_service": resourceConsulAgentService(), + "consul_autopilot_config": resourceConsulAutopilotConfig(), + "consul_catalog_entry": resourceConsulCatalogEntry(), + "consul_certificate_authority": resourceConsulCertificateAuthority(), + "consul_config_entry_v2_exported_services": resourceConsulV2ExportedServices(), + "consul_config_entry_service_defaults": resourceFromConfigEntryImplementation(&serviceDefaults{}), + "consul_config_entry_service_intentions": resourceFromConfigEntryImplementation(&serviceIntentions{}), + "consul_config_entry_service_resolver": resourceFromConfigEntryImplementation(&serviceResolver{}), + "consul_config_entry_service_router": resourceFromConfigEntryImplementation(&serviceRouter{}), + "consul_config_entry_service_splitter": resourceFromConfigEntryImplementation(&serviceSplitter{}), + "consul_config_entry": resourceConsulConfigEntry(), + "consul_intention": resourceConsulIntention(), + "consul_key_prefix": resourceConsulKeyPrefix(), + "consul_keys": resourceConsulKeys(), + "consul_license": resourceConsulLicense(), + "consul_namespace_policy_attachment": resourceConsulNamespacePolicyAttachment(), + "consul_namespace_role_attachment": resourceConsulNamespaceRoleAttachment(), + "consul_namespace": resourceConsulNamespace(), + "consul_network_area": resourceConsulNetworkArea(), + "consul_node": resourceConsulNode(), + "consul_peering_token": resourceSourceConsulPeeringToken(), + "consul_peering": resourceSourceConsulPeering(), + "consul_prepared_query": resourceConsulPreparedQuery(), + "consul_service": resourceConsulService(), }, ConfigureFunc: providerConfigure, diff --git a/go.mod b/go.mod index 3103335a..1512e815 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,11 @@ module github.com/hashicorp/terraform-provider-consul +// We need to use a replace directive instead of directly pinning because `api` requires version `0.5.1` and will clobber the pin, but not the replace directive. +replace github.com/hashicorp/consul/proto-public => github.com/hashicorp/consul/proto-public v0.1.2-0.20240208173503-e72afa654d22 + require ( - github.com/hashicorp/consul/api v1.26.1-rc1 + github.com/hashicorp/consul/api v1.10.1-0.20240209095413-ae9fb4c83d42 + github.com/hashicorp/consul/proto-public v0.5.2 github.com/hashicorp/errwrap v1.1.0 github.com/hashicorp/terraform-plugin-sdk v1.17.2 github.com/mitchellh/mapstructure v1.5.0 @@ -39,7 +43,7 @@ require ( github.com/google/go-cmp v0.5.9 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/gax-go/v2 v2.7.1 // indirect - github.com/hashicorp/consul/sdk v0.14.3-rc1 + github.com/hashicorp/consul/sdk v0.15.0 github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter v1.7.0 // indirect @@ -90,8 +94,8 @@ require ( golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.114.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 2f646dc9..0f4fd6f1 100644 --- a/go.sum +++ b/go.sum @@ -410,10 +410,16 @@ github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6c github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.26.1-rc1 h1:eO+53vwWxEV2TMbTVrJbXp2TJjJNv+Nxij8j+xi3yOc= -github.com/hashicorp/consul/api v1.26.1-rc1/go.mod h1:ZKnaWXL2r23i+SPmEj1H5YsRNUS/uUzB2uhmD2QY4IY= -github.com/hashicorp/consul/sdk v0.14.3-rc1 h1:kE0dLXXTnvm67PNRE527XpSwqi5vwWoP+VkNHdBBR7o= -github.com/hashicorp/consul/sdk v0.14.3-rc1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= +github.com/hashicorp/consul/api v1.10.1-0.20240122152324-758ddf84e9c9 h1:qaS6rE768dt5hGPl2y4DIABXF4eA23BNSmWFpEr3kWQ= +github.com/hashicorp/consul/api v1.10.1-0.20240122152324-758ddf84e9c9/go.mod h1:gInwZGrnWlE1Vvq6rSD5pUf6qwNa69NTLLknbdwQRUk= +github.com/hashicorp/consul/api v1.10.1-0.20240209045659-981288e4082a h1:j2KLnImjuFUjhYK7Ly63dMVW7GWRFuPn5L1RIFoDye0= +github.com/hashicorp/consul/api v1.10.1-0.20240209045659-981288e4082a/go.mod h1:gInwZGrnWlE1Vvq6rSD5pUf6qwNa69NTLLknbdwQRUk= +github.com/hashicorp/consul/api v1.10.1-0.20240209095413-ae9fb4c83d42 h1:72SNfzBZccnJQ6diaGmUT6vHHzG5lcb4GiYAaED9kcM= +github.com/hashicorp/consul/api v1.10.1-0.20240209095413-ae9fb4c83d42/go.mod h1:XOFRmXaFsTMJIU9jGh0iZQs54SizswiA7lIGfOOX0j0= +github.com/hashicorp/consul/proto-public v0.1.2-0.20240208173503-e72afa654d22 h1:PQQfwXeitSSyeXffKDTB/pOpxOKodgXEiNYcEFpgEMI= +github.com/hashicorp/consul/proto-public v0.1.2-0.20240208173503-e72afa654d22/go.mod h1:JF6983XNCzvw4wDNOLEwLqOq2IPw7iyT+pkswHSz08U= +github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU= +github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -925,8 +931,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -940,8 +946,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 6559cb784c56a4615490c05ea33990d90e672049 Mon Sep 17 00:00:00 2001 From: skpratt Date: Mon, 26 Feb 2024 23:22:55 -0600 Subject: [PATCH 2/5] use api client raw methods --- ...onsul_config_entry_v2_exported_services.go | 5 +- ..._config_entry_v2_exported_services_test.go | 55 ++++++++++++---- ...onsul_config_entry_v2_exported_services.go | 21 +++---- ..._config_entry_v2_exported_services_test.go | 12 ++-- consul/v2_resource_provider_helper.go | 63 +++++++++++++++++++ .../config_entry_v2_exported_services.md | 34 ++++++++++ .../config_entry_v2_exported_services.md | 34 ++++++++++ go.mod | 4 +- go.sum | 12 ++-- 9 files changed, 199 insertions(+), 41 deletions(-) create mode 100644 consul/v2_resource_provider_helper.go create mode 100644 docs/data-sources/config_entry_v2_exported_services.md create mode 100644 docs/resources/config_entry_v2_exported_services.md diff --git a/consul/data_source_consul_config_entry_v2_exported_services.go b/consul/data_source_consul_config_entry_v2_exported_services.go index 0bc211c1..af7706a0 100644 --- a/consul/data_source_consul_config_entry_v2_exported_services.go +++ b/consul/data_source_consul_config_entry_v2_exported_services.go @@ -7,7 +7,6 @@ import ( "encoding/json" "fmt" - "github.com/hashicorp/consul/api" pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2" "github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -84,12 +83,12 @@ func dataSourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interfa client, qOpts, _ := getClient(d, meta) name := d.Get("name").(string) kind := d.Get("kind").(string) - gvk := &api.GVK{ + gvk := &GVK{ //&api.GVK{ Group: "multicluster", Version: "v2", Kind: kind, } - resp, err := client.Resource().Read(gvk, name, qOpts) + resp, err := v2MulticlusterRead(client, gvk, name, qOpts) if err != nil || resp == nil { return fmt.Errorf("exported services config not found: %s", name) } diff --git a/consul/data_source_consul_config_entry_v2_exported_services_test.go b/consul/data_source_consul_config_entry_v2_exported_services_test.go index e6e7124a..dc011f0e 100644 --- a/consul/data_source_consul_config_entry_v2_exported_services_test.go +++ b/consul/data_source_consul_config_entry_v2_exported_services_test.go @@ -8,17 +8,20 @@ import ( ) func TestAccDataExportedServicesV2_basic(t *testing.T) { - providers, _ := startTestServer(t) + providers, client := startTestServer(t) resource.Test(t, resource.TestCase{ Providers: providers, + PreCheck: func() { skipTestOnConsulCommunityEdition(t) }, Steps: []resource.TestStep{ { Config: testAccDataSourceExportedServicesV2ConfigNotFound, + SkipFunc: skipIfConsulVersionLT(client, "1.18.0"), ExpectError: regexp.MustCompile(`exported services config not found: not-found`), }, { - Config: testAccDataSourceExportedServicesV2ConfigBasic, + Config: testAccDataSourceExportedServicesV2ConfigBasic, + SkipFunc: skipIfConsulVersionLT(client, "1.18.0"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "name", "test"), resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "kind", "ExportedServices"), @@ -29,33 +32,59 @@ func TestAccDataExportedServicesV2_basic(t *testing.T) { ), }, { - Config: testAccDataSourceComputedExportedServicesV2ConfigBasic, + Config: testAccDataSourceNamespaceExportedServicesV2ConfigBasic, + SkipFunc: skipIfConsulVersionLT(client, "1.18.0"), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "name", "default"), - resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "kind", "ComputedExportedServices"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "name", "test"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "kind", "NamespaceExportedServices"), resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "partition", "default"), - resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "services.0", "s1"), - resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "sameness_group_consumers.0", "sg1"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "partition_consumers.0", "default"), + ), + }, + { + Config: testAccDataSourcePartitionExportedServicesV2ConfigBasic, + SkipFunc: skipIfConsulVersionLT(client, "1.18.0"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "name", "test"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "kind", "PartitionExportedServices"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "partition", "default"), + resource.TestCheckResourceAttr("data.consul_config_entry_v2_exported_services.read", "peer_consumers.0", "peer1"), ), }, }, }) } -const testAccDataSourceComputedExportedServicesV2ConfigBasic = ` +const testAccDataSourcePartitionExportedServicesV2ConfigBasic = ` resource "consul_config_entry_v2_exported_services" "test" { name = "test" - kind = "ExportedServices" + kind = "PartitionExportedServices" + partition = "default" + peer_consumers = ["peer1"] +} + +data "consul_config_entry_v2_exported_services" "read" { + name = consul_config_entry_v2_exported_services.test.name + kind = consul_config_entry_v2_exported_services.test.kind + namespace = consul_config_entry_v2_exported_services.test.namespace + partition = consul_config_entry_v2_exported_services.test.partition +} +` + +const testAccDataSourceNamespaceExportedServicesV2ConfigBasic = ` +resource "consul_config_entry_v2_exported_services" "test" { + name = "test" + kind = "NamespaceExportedServices" namespace = "default" partition = "default" - services = ["s1"] partition_consumers = ["default"] } data "consul_config_entry_v2_exported_services" "read" { - name = "default" - kind = "ComputedExportedServices" - partition = "default" + name = consul_config_entry_v2_exported_services.test.name + kind = consul_config_entry_v2_exported_services.test.kind + namespace = consul_config_entry_v2_exported_services.test.namespace + partition = consul_config_entry_v2_exported_services.test.partition } ` diff --git a/consul/resource_consul_config_entry_v2_exported_services.go b/consul/resource_consul_config_entry_v2_exported_services.go index 9ad4bf34..cc68ff45 100644 --- a/consul/resource_consul_config_entry_v2_exported_services.go +++ b/consul/resource_consul_config_entry_v2_exported_services.go @@ -7,7 +7,6 @@ import ( "encoding/json" "fmt" - "github.com/hashicorp/consul/api" pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2" "github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -94,10 +93,10 @@ func resourceConsulV2ExportedServicesCreate(d *schema.ResourceData, meta interfa } func resourceConsulV2ExportedServicesUpdate(d *schema.ResourceData, meta interface{}) error { - client, qOpts, _ := getClient(d, meta) + client, _, wOpts := getClient(d, meta) name := d.Get("name").(string) kind := d.Get("kind").(string) - gvk := &api.GVK{ + gvk := &GVK{ Group: "multicluster", Version: "v2", Kind: kind, @@ -112,20 +111,20 @@ func resourceConsulV2ExportedServicesUpdate(d *schema.ResourceData, meta interfa consumers = append(consumers, map[string]any{"partition": ap}) } samenessConsumers := d.Get("sameness_group_consumers").([]interface{}) - for _, ap := range samenessConsumers { - consumers = append(consumers, map[string]any{"sameness_group": ap}) + for _, sg := range samenessConsumers { + consumers = append(consumers, map[string]any{"sameness_group": sg}) } data := map[string]any{"consumers": consumers} services := d.Get("services").([]interface{}) if len(services) > 0 { data["services"] = services } - wReq := &api.WriteRequest{ + wReq := &V2WriteRequest{ Metadata: nil, Data: data, Owner: nil, } - resp, _, err := client.Resource().Apply(gvk, name, qOpts, wReq) + resp, _, err := v2MulticlusterApply(client, gvk, name, wOpts, wReq) if err != nil || resp == nil { return fmt.Errorf("failed to write exported services config '%s': %v", name, err) } @@ -142,12 +141,12 @@ func resourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interface client, qOpts, _ := getClient(d, meta) name := d.Get("name").(string) kind := d.Get("kind").(string) - gvk := &api.GVK{ + gvk := &GVK{ Group: "multicluster", Version: "v2", Kind: kind, } - resp, err := client.Resource().Read(gvk, name, qOpts) + resp, err := v2MulticlusterRead(client, gvk, name, qOpts) if err != nil || resp == nil { return fmt.Errorf("exported services config not found: %s", name) } @@ -196,11 +195,11 @@ func resourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interface func resourceConsulV2ExportedServicesDelete(d *schema.ResourceData, meta interface{}) error { client, qOpts, _ := getClient(d, meta) - gvk := &api.GVK{ + gvk := &GVK{ Group: "multicluster", Version: "v2", Kind: "ExportedServices", } name := d.Get("name").(string) - return client.Resource().Delete(gvk, name, qOpts) + return v2MulticlusterDelete(client, gvk, name, qOpts) } diff --git a/consul/resource_consul_config_entry_v2_exported_services_test.go b/consul/resource_consul_config_entry_v2_exported_services_test.go index ddfe4ad2..083d8afb 100644 --- a/consul/resource_consul_config_entry_v2_exported_services_test.go +++ b/consul/resource_consul_config_entry_v2_exported_services_test.go @@ -10,13 +10,15 @@ import ( ) func TestAccConsulExportedServicesV2_basic(t *testing.T) { - providers, _ := startTestServer(t) + providers, client := startTestServer(t) resource.Test(t, resource.TestCase{ Providers: providers, + PreCheck: func() { skipTestOnConsulCommunityEdition(t) }, Steps: []resource.TestStep{ { - Config: testAccConsulExportedServicesV2Basic, + Config: testAccConsulExportedServicesV2Basic, + SkipFunc: skipIfConsulVersionLT(client, "1.18.0"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.test", "name", "test"), resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.test", "kind", "ExportedServices"), @@ -29,7 +31,8 @@ func TestAccConsulExportedServicesV2_basic(t *testing.T) { ), }, { - Config: testAccConsulNamespaceExportedServicesV2Basic, + Config: testAccConsulNamespaceExportedServicesV2Basic, + SkipFunc: skipIfConsulVersionLT(client, "1.18.0"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.nstest", "name", "nstest"), resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.nstest", "kind", "NamespaceExportedServices"), @@ -42,7 +45,8 @@ func TestAccConsulExportedServicesV2_basic(t *testing.T) { ), }, { - Config: testAccConsulPartitionExportedServicesV2Basic, + Config: testAccConsulPartitionExportedServicesV2Basic, + SkipFunc: skipIfConsulVersionLT(client, "1.18.0"), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.ptest", "name", "ptest"), resource.TestCheckResourceAttr("consul_config_entry_v2_exported_services.ptest", "kind", "PartitionExportedServices"), diff --git a/consul/v2_resource_provider_helper.go b/consul/v2_resource_provider_helper.go new file mode 100644 index 00000000..342cba35 --- /dev/null +++ b/consul/v2_resource_provider_helper.go @@ -0,0 +1,63 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package consul + +import ( + "fmt" + "strings" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +type GVK struct { + Group string + Version string + Kind string +} + +type V2WriteRequest struct { + Metadata map[string]string `json:"metadata"` + Data map[string]any `json:"data"` + Owner *pbresource.ID `json:"owner"` +} + +type V2WriteResponse struct { + Metadata map[string]string `json:"metadata"` + Data map[string]any `json:"data"` + Owner *pbresource.ID `json:"owner,omitempty"` + ID *pbresource.ID `json:"id"` + Version string `json:"version"` + Generation string `json:"generation"` + Status map[string]any `json:"status"` +} + +func v2MulticlusterRead(client *api.Client, gvk *GVK, resourceName string, q *api.QueryOptions) (map[string]interface{}, error) { + endpoint := strings.ToLower(fmt.Sprintf("/api/%s/%s/%s/%s", gvk.Group, gvk.Version, gvk.Kind, resourceName)) + var out map[string]interface{} + _, err := client.Raw().Query(endpoint, &out, q) + if err != nil { + return nil, err + } + return out, nil +} + +func v2MulticlusterDelete(client *api.Client, gvk *GVK, resourceName string, q *api.QueryOptions) error { + endpoint := strings.ToLower(fmt.Sprintf("/api/%s/%s/%s/%s", gvk.Group, gvk.Version, gvk.Kind, resourceName)) + _, err := client.Raw().Delete(endpoint, q) + if err != nil { + return err + } + return nil +} + +func v2MulticlusterApply(client *api.Client, gvk *GVK, resourceName string, w *api.WriteOptions, payload *V2WriteRequest) (*V2WriteResponse, *api.WriteMeta, error) { + endpoint := strings.ToLower(fmt.Sprintf("/api/%s/%s/%s/%s", gvk.Group, gvk.Version, gvk.Kind, resourceName)) + out := &V2WriteResponse{} + wm, err := client.Raw().Write(endpoint, payload, out, w) + if err != nil { + return nil, nil, err + } + return out, wm, nil +} diff --git a/docs/data-sources/config_entry_v2_exported_services.md b/docs/data-sources/config_entry_v2_exported_services.md new file mode 100644 index 00000000..6b0e6665 --- /dev/null +++ b/docs/data-sources/config_entry_v2_exported_services.md @@ -0,0 +1,34 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "consul_config_entry_v2_exported_services Data Source - terraform-provider-consul" +subcategory: "" +description: |- + +--- + +# consul_config_entry_v2_exported_services (Data Source) + + + + + + +## Schema + +### Required + +- `kind` (String) The kind of exported services config (ExportedServices, NamespaceExportedServices, PartitionExportedServices). +- `name` (String) The name of the config entry to read. + +### Optional + +- `namespace` (String) The namespace the config entry is associated with. +- `partition` (String) The partition the config entry is associated with. +- `partition_consumers` (List of String) The exported service partition consumers. +- `peer_consumers` (List of String) The exported service peer consumers. +- `sameness_group_consumers` (List of String) The exported service sameness group consumers. +- `services` (List of String) The exported services. + +### Read-Only + +- `id` (String) The ID of this resource. diff --git a/docs/resources/config_entry_v2_exported_services.md b/docs/resources/config_entry_v2_exported_services.md new file mode 100644 index 00000000..5e65e799 --- /dev/null +++ b/docs/resources/config_entry_v2_exported_services.md @@ -0,0 +1,34 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "consul_config_entry_v2_exported_services Resource - terraform-provider-consul" +subcategory: "" +description: |- + +--- + +# consul_config_entry_v2_exported_services (Resource) + + + + + + +## Schema + +### Required + +- `kind` (String) The kind of exported services config (ExportedServices, NamespaceExportedServices, PartitionExportedServices). +- `name` (String) The name of the config entry to read. +- `partition` (String) The partition the config entry is associated with. + +### Optional + +- `namespace` (String) The namespace the config entry is associated with. +- `partition_consumers` (List of String) The exported service partition consumers. +- `peer_consumers` (List of String) The exported service peer consumers. +- `sameness_group_consumers` (List of String) The exported service sameness group consumers. +- `services` (List of String) The exported services. + +### Read-Only + +- `id` (String) The ID of this resource. diff --git a/go.mod b/go.mod index 1512e815..f21f9af5 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ module github.com/hashicorp/terraform-provider-consul replace github.com/hashicorp/consul/proto-public => github.com/hashicorp/consul/proto-public v0.1.2-0.20240208173503-e72afa654d22 require ( - github.com/hashicorp/consul/api v1.10.1-0.20240209095413-ae9fb4c83d42 + github.com/hashicorp/consul/api v1.10.1-0.20240227042019-fd46676f3cb7 github.com/hashicorp/consul/proto-public v0.5.2 github.com/hashicorp/errwrap v1.1.0 github.com/hashicorp/terraform-plugin-sdk v1.17.2 @@ -101,7 +101,7 @@ require ( google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/grpc v1.56.3 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.32.0 ) go 1.21 diff --git a/go.sum b/go.sum index 0f4fd6f1..bb8685d5 100644 --- a/go.sum +++ b/go.sum @@ -410,12 +410,8 @@ github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6c github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.10.1-0.20240122152324-758ddf84e9c9 h1:qaS6rE768dt5hGPl2y4DIABXF4eA23BNSmWFpEr3kWQ= -github.com/hashicorp/consul/api v1.10.1-0.20240122152324-758ddf84e9c9/go.mod h1:gInwZGrnWlE1Vvq6rSD5pUf6qwNa69NTLLknbdwQRUk= -github.com/hashicorp/consul/api v1.10.1-0.20240209045659-981288e4082a h1:j2KLnImjuFUjhYK7Ly63dMVW7GWRFuPn5L1RIFoDye0= -github.com/hashicorp/consul/api v1.10.1-0.20240209045659-981288e4082a/go.mod h1:gInwZGrnWlE1Vvq6rSD5pUf6qwNa69NTLLknbdwQRUk= -github.com/hashicorp/consul/api v1.10.1-0.20240209095413-ae9fb4c83d42 h1:72SNfzBZccnJQ6diaGmUT6vHHzG5lcb4GiYAaED9kcM= -github.com/hashicorp/consul/api v1.10.1-0.20240209095413-ae9fb4c83d42/go.mod h1:XOFRmXaFsTMJIU9jGh0iZQs54SizswiA7lIGfOOX0j0= +github.com/hashicorp/consul/api v1.10.1-0.20240227042019-fd46676f3cb7 h1:SAnmime+Oi0TUG6q4uf0J9K/qgA5zmlvQCLxLO/hpGs= +github.com/hashicorp/consul/api v1.10.1-0.20240227042019-fd46676f3cb7/go.mod h1:kAuXnZ0r0y/uLXcy8+aexlGVonsgt3nR552fwkbBnMc= github.com/hashicorp/consul/proto-public v0.1.2-0.20240208173503-e72afa654d22 h1:PQQfwXeitSSyeXffKDTB/pOpxOKodgXEiNYcEFpgEMI= github.com/hashicorp/consul/proto-public v0.1.2-0.20240208173503-e72afa654d22/go.mod h1:JF6983XNCzvw4wDNOLEwLqOq2IPw7iyT+pkswHSz08U= github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU= @@ -1232,8 +1228,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 6f06e0cc1b514b5625592b420378626010a05ffd Mon Sep 17 00:00:00 2001 From: skpratt Date: Tue, 5 Mar 2024 12:27:03 -0600 Subject: [PATCH 3/5] update deps --- .github/workflows/test.yaml | 2 +- go.mod | 7 ++----- go.sum | 8 ++++---- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 43ef980d..4bcfa122 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - consul-version: [1.16.2, 1.17.0-rc1] + consul-version: [1.16.6, 1.17.3, 1.18.0] os: [ubuntu-latest] runs-on: ${{ matrix.os }} steps: diff --git a/go.mod b/go.mod index f21f9af5..ab2ec304 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,8 @@ module github.com/hashicorp/terraform-provider-consul -// We need to use a replace directive instead of directly pinning because `api` requires version `0.5.1` and will clobber the pin, but not the replace directive. -replace github.com/hashicorp/consul/proto-public => github.com/hashicorp/consul/proto-public v0.1.2-0.20240208173503-e72afa654d22 - require ( - github.com/hashicorp/consul/api v1.10.1-0.20240227042019-fd46676f3cb7 - github.com/hashicorp/consul/proto-public v0.5.2 + github.com/hashicorp/consul/api v1.10.1-0.20240305172350-4e7982a5b707 + github.com/hashicorp/consul/proto-public v0.6.0 github.com/hashicorp/errwrap v1.1.0 github.com/hashicorp/terraform-plugin-sdk v1.17.2 github.com/mitchellh/mapstructure v1.5.0 diff --git a/go.sum b/go.sum index bb8685d5..f4176150 100644 --- a/go.sum +++ b/go.sum @@ -410,10 +410,10 @@ github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6c github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.10.1-0.20240227042019-fd46676f3cb7 h1:SAnmime+Oi0TUG6q4uf0J9K/qgA5zmlvQCLxLO/hpGs= -github.com/hashicorp/consul/api v1.10.1-0.20240227042019-fd46676f3cb7/go.mod h1:kAuXnZ0r0y/uLXcy8+aexlGVonsgt3nR552fwkbBnMc= -github.com/hashicorp/consul/proto-public v0.1.2-0.20240208173503-e72afa654d22 h1:PQQfwXeitSSyeXffKDTB/pOpxOKodgXEiNYcEFpgEMI= -github.com/hashicorp/consul/proto-public v0.1.2-0.20240208173503-e72afa654d22/go.mod h1:JF6983XNCzvw4wDNOLEwLqOq2IPw7iyT+pkswHSz08U= +github.com/hashicorp/consul/api v1.10.1-0.20240305172350-4e7982a5b707 h1:MrRUoVSf9aqxENuxLggbawazAkaiHMMX4KZR8Q0lv/s= +github.com/hashicorp/consul/api v1.10.1-0.20240305172350-4e7982a5b707/go.mod h1:GmIks4tBN5K6CD5UG2yS5IHR/UryqfZ31YBqPh/pA8E= +github.com/hashicorp/consul/proto-public v0.6.0 h1:9qrBujmoTB5gQQ84kQO+YWvhjgYoYBNrOoHdo4cpHHM= +github.com/hashicorp/consul/proto-public v0.6.0/go.mod h1:JF6983XNCzvw4wDNOLEwLqOq2IPw7iyT+pkswHSz08U= github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU= github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= From 97ec08fe30f0f13fcbf398b4ac50ea8a392fc5ca Mon Sep 17 00:00:00 2001 From: skpratt Date: Wed, 6 Mar 2024 09:28:59 -0600 Subject: [PATCH 4/5] 1.18 bind type error fix --- consul/resource_consul_acl_binding_rule_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consul/resource_consul_acl_binding_rule_test.go b/consul/resource_consul_acl_binding_rule_test.go index 9e207dbf..2a8e546b 100644 --- a/consul/resource_consul_acl_binding_rule_test.go +++ b/consul/resource_consul_acl_binding_rule_test.go @@ -74,7 +74,7 @@ func TestAccConsulACLBindingRule_basic(t *testing.T) { }, { Config: testResourceACLBindingRuleConfig_wrongType, - ExpectError: regexp.MustCompile(`Invalid Binding Rule: unknown BindType "foobar"`), + ExpectError: regexp.MustCompile(`unknown BindType "foobar"`), }, }, }) From 8fdc4054a53989505509063976b16951b92f4178 Mon Sep 17 00:00:00 2001 From: skpratt Date: Thu, 21 Mar 2024 02:19:20 -0500 Subject: [PATCH 5/5] edits --- ...onsul_config_entry_v2_exported_services.go | 10 ++++----- ...onsul_config_entry_v2_exported_services.go | 22 +++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/consul/data_source_consul_config_entry_v2_exported_services.go b/consul/data_source_consul_config_entry_v2_exported_services.go index af7706a0..12d4a180 100644 --- a/consul/data_source_consul_config_entry_v2_exported_services.go +++ b/consul/data_source_consul_config_entry_v2_exported_services.go @@ -83,13 +83,13 @@ func dataSourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interfa client, qOpts, _ := getClient(d, meta) name := d.Get("name").(string) kind := d.Get("kind").(string) - gvk := &GVK{ //&api.GVK{ - Group: "multicluster", - Version: "v2", + gvk := &GVK{ + Group: pbmulticluster.GroupName, + Version: pbmulticluster.Version, Kind: kind, } resp, err := v2MulticlusterRead(client, gvk, name, qOpts) - if err != nil || resp == nil { + if err != nil || resp == nil || resp["id"] == nil || resp["data"] == nil { return fmt.Errorf("exported services config not found: %s", name) } respData, err := json.Marshal(resp["data"]) @@ -106,7 +106,7 @@ func dataSourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interfa } id := &pbresource.ID{} if err = protojson.Unmarshal(respID, id); err != nil { - return fmt.Errorf("Failed to unmarshal to proto message: %v", err) + return fmt.Errorf("failed to unmarshal to proto message: %v", err) } var partitions []string var peers []string diff --git a/consul/resource_consul_config_entry_v2_exported_services.go b/consul/resource_consul_config_entry_v2_exported_services.go index cc68ff45..2bb1bb19 100644 --- a/consul/resource_consul_config_entry_v2_exported_services.go +++ b/consul/resource_consul_config_entry_v2_exported_services.go @@ -102,16 +102,13 @@ func resourceConsulV2ExportedServicesUpdate(d *schema.ResourceData, meta interfa Kind: kind, } var consumers []map[string]any - peerConsumers := d.Get("peer_consumers").([]interface{}) - for _, p := range peerConsumers { + for _, p := range d.Get("peer_consumers").([]interface{}) { consumers = append(consumers, map[string]any{"peer": p}) } - partitionConsumers := d.Get("partition_consumers").([]interface{}) - for _, ap := range partitionConsumers { + for _, ap := range d.Get("partition_consumers").([]interface{}) { consumers = append(consumers, map[string]any{"partition": ap}) } - samenessConsumers := d.Get("sameness_group_consumers").([]interface{}) - for _, sg := range samenessConsumers { + for _, sg := range d.Get("sameness_group_consumers").([]interface{}) { consumers = append(consumers, map[string]any{"sameness_group": sg}) } data := map[string]any{"consumers": consumers} @@ -142,8 +139,8 @@ func resourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interface name := d.Get("name").(string) kind := d.Get("kind").(string) gvk := &GVK{ - Group: "multicluster", - Version: "v2", + Group: pbmulticluster.GroupName, + Version: pbmulticluster.Version, Kind: kind, } resp, err := v2MulticlusterRead(client, gvk, name, qOpts) @@ -164,7 +161,7 @@ func resourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interface } id := &pbresource.ID{} if err = protojson.Unmarshal(respID, id); err != nil { - return fmt.Errorf("Failed to unmarshal to proto message: %v", err) + return fmt.Errorf("failed to unmarshal to proto message: %v", err) } var partitions []string var peers []string @@ -195,10 +192,11 @@ func resourceConsulV2ExportedServicesRead(d *schema.ResourceData, meta interface func resourceConsulV2ExportedServicesDelete(d *schema.ResourceData, meta interface{}) error { client, qOpts, _ := getClient(d, meta) + kind := d.Get("kind").(string) gvk := &GVK{ - Group: "multicluster", - Version: "v2", - Kind: "ExportedServices", + Group: pbmulticluster.GroupName, + Version: pbmulticluster.Version, + Kind: kind, } name := d.Get("name").(string) return v2MulticlusterDelete(client, gvk, name, qOpts)