Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add consul_config_entry datasource #318

Merged
merged 3 commits into from
Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions consul/data_source_consul_config_entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package consul

import (
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func dataSourceConsulConfigEntry() *schema.Resource {
return &schema.Resource{
Read: dataSourceConsulConfigEntryRead,

Schema: map[string]*schema.Schema{
"kind": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The kind of config entry to read.",
},

"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The name of the config entry to read.",
},

"partition": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: "The partition the config entry is associated with.",
},

"namespace": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: "The namespace the config entry is associated with.",
},

"config_json": {
Type: schema.TypeString,
Computed: true,
Description: "The configuration of the config entry.",
},
},
}
}

func dataSourceConsulConfigEntryRead(d *schema.ResourceData, meta interface{}) error {
client, qOpts, _ := getClient(d, meta)

kind := d.Get("kind").(string)
name := d.Get("name").(string)

configEntry, _, err := client.ConfigEntries().Get(kind, name, qOpts)
if err != nil {
return fmt.Errorf("failed to read config entry %s/%s: %w", kind, name, err)
}

// Config Entries are too complex to write as maps for now so we save their JSON representation
data, err := configEntryToMap(configEntry)
if err != nil {
return err
}

d.SetId(fmt.Sprintf("%s/%s", kind, name))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't id collide with other config entries with the same kind/name in other partitions/namespaces?

Copy link
Collaborator Author

@remilapeyre remilapeyre Dec 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id in Terraform resources or datasources is often unique but does not need to, when objects don't have a specific ID it can happen that they have the same of another.

For example Consul has this at https://github.com/hashicorp/terraform-provider-consul/blob/master/consul/resource_consul_keys.go#L188-L191 where all consul_keys resources will have the same id no matter the keys being set and another occurence of this in the Vault provider is at https://github.com/hashicorp/terraform-provider-vault/blob/main/vault/resource_generic_endpoint.go#L111 where multiple vault_generic_endpoint resources can have the same id despite being in different namespace.

Here because config entries do not have IDs and the user won't use it it does not matter what placeholder we use.


sw := newStateWriter(d)
sw.setJson("config_json", data)

return sw.error()
}
56 changes: 56 additions & 0 deletions consul/data_source_consul_config_entry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package consul

import (
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

func TestAccDataConsulConfigEntry_basic(t *testing.T) {
providers, _ := startTestServer(t)

resource.Test(t, resource.TestCase{
Providers: providers,
Steps: []resource.TestStep{
{
Config: testAccDataConsulConfigEntryMissing,
ExpectError: regexp.MustCompile(`failed to read config entry service-defaults/foo: Unexpected response code: 404`),
},
{
Config: testAccDataConsulConfigEntry,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.consul_config_entry.read", "config_json", "{\"Expose\":{},\"MeshGateway\":{},\"Protocol\":\"https\",\"TransparentProxy\":{}}"),
resource.TestCheckResourceAttr("data.consul_config_entry.read", "id", "service-defaults/foo"),
resource.TestCheckResourceAttr("data.consul_config_entry.read", "kind", "service-defaults"),
resource.TestCheckResourceAttr("data.consul_config_entry.read", "name", "foo"),
),
},
},
})
}

const testAccDataConsulConfigEntry = `
resource "consul_config_entry" "test" {
name = "foo"
kind = "service-defaults"

config_json = jsonencode({
MeshGateway = {}
Protocol = "https"
TransparentProxy = {}
})
}

data "consul_config_entry" "read" {
name = consul_config_entry.test.name
kind = consul_config_entry.test.kind
}
`

const testAccDataConsulConfigEntryMissing = `
data "consul_config_entry" "read" {
name = "foo"
kind = "service-defaults"
}
`
3 changes: 2 additions & 1 deletion consul/resource_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ func Provider() terraform.ResourceProvider {
"consul_network_segments": dataSourceConsulNetworkSegments(),
"consul_network_area_members": dataSourceConsulNetworkAreaMembers(),
"consul_datacenters": dataSourceConsulDatacenters(),
"consul_config_entry": dataSourceConsulConfigEntry(),
"consul_peering": dataSourceConsulPeering(),
"consul_peerings": dataSourceConsulPeerings(),

Expand Down Expand Up @@ -303,7 +304,7 @@ func (sw *stateWriter) setJson(key string, value interface{}) {
if err != nil {
sw.errors = append(
sw.errors,
fmt.Sprintf("failed to marshal '%s': %v", key, err),
fmt.Sprintf(" - failed to marshal '%s': %v", key, err),
)
return
}
Expand Down