Skip to content

Commit

Permalink
ec_deployments datasource: Add tags filter (#248)
Browse files Browse the repository at this point in the history
Adds a tags filter to the `ec_deployments` datasource:

```
data "ec_deployments" "example" {
  tags = {
      "foo" = "bar"
  }
}
```

Co-authored-by: Marc Lopez Rubio <[email protected]>
  • Loading branch information
neiljbrookes and marclop authored Mar 8, 2021
1 parent 7f31986 commit 1fd5515
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 10 deletions.
5 changes: 5 additions & 0 deletions docs/data-sources/ec_deployments.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ data "ec_deployments" "example" {
name_prefix = "test"
deployment_template_id = "azure-compute-optimized"
tags = {
"foo" = "bar"
}
elasticsearch {
healthy = "true"
}
Expand All @@ -37,6 +41,7 @@ data "ec_deployments" "example" {

* `name_prefix` - Prefix that one or several deployment names have in common.
* `deployment_template_id` - ID of the deployment template used to create the deployment.
* `tags` - Key value map of arbitrary string tags for the deployment.
* `healthy` - Overall health status of the deployment.
* `elasticsearch` - Filter by Elasticsearch resource kind status or configuration.
* `elasticsearch.#.status` - Resource kind status (Available statuses are: initializing, stopping, stopped, rebooting, restarting, reconfiguring, and started).
Expand Down
28 changes: 22 additions & 6 deletions ec/acc/datasource_tags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,16 @@ import (
// * Create a deployment resource with tags.
// * Create a datasource from the resource.
// * Ensure tags exist.
// * Create a datasource with filters for the unique tag
// * Ensure that only a single deployment is returned
func TestAccDatasource_basic_tags(t *testing.T) {

datasourceName := "data.ec_deployment.tags"
datasourceName := "data.ec_deployment.tagdata"
filterDatasourceName := "data.ec_deployments.tagfilter"
depCfg := "testdata/datasource_tags.tf"
randomName := prefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
cfg := fixtureAccTagsDataSource(t, depCfg, randomName, getRegion(), defaultTemplate)
testID := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
randomName := prefix + testID
cfg := fixtureAccTagsDataSource(t, depCfg, randomName, getRegion(), defaultTemplate, testID)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand All @@ -46,16 +50,28 @@ func TestAccDatasource_basic_tags(t *testing.T) {
{
Config: cfg,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(datasourceName, "tags.%", "2"),
// Check the "ec_deployment" datasource
resource.TestCheckResourceAttr(datasourceName, "tags.%", "3"),
resource.TestCheckResourceAttr(datasourceName, "tags.foo", "bar"),
resource.TestCheckResourceAttr(datasourceName, "tags.bar", "baz"),
resource.TestCheckResourceAttr(datasourceName, "tags.test_id", testID),
),
},
{
Config: cfg,
Check: resource.ComposeAggregateTestCheckFunc(
// Check the "ec_deployments" datasource, which filters on tags.
resource.TestCheckResourceAttrSet(filterDatasourceName, "return_count"),
resource.TestCheckResourceAttr(filterDatasourceName, "return_count", "1"),
resource.TestCheckResourceAttr(filterDatasourceName, "deployments.#", "1"),
resource.TestCheckResourceAttrSet(filterDatasourceName, "deployments.0.deployment_id"),
),
},
},
})
}

func fixtureAccTagsDataSource(t *testing.T, fileName, name, region string, depTpl string) string {
func fixtureAccTagsDataSource(t *testing.T, fileName, name, region string, depTpl string, testID string) string {
t.Helper()

deploymentTpl := setDefaultTemplate(region, depTpl)
Expand All @@ -64,6 +80,6 @@ func fixtureAccTagsDataSource(t *testing.T, fileName, name, region string, depTp
t.Fatal(err)
}
return fmt.Sprintf(string(b),
region, name, region, deploymentTpl,
region, name, region, deploymentTpl, testID, testID,
)
}
13 changes: 10 additions & 3 deletions ec/acc/testdata/datasource_tags.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ resource "ec_deployment" "tags" {
version = data.ec_stack.latest.version
deployment_template_id = "%s"
tags = {
"foo" = "bar"
"bar" = "baz"
"foo" = "bar"
"bar" = "baz"
"test_id" = "%s"
}

elasticsearch {
Expand All @@ -21,6 +22,12 @@ resource "ec_deployment" "tags" {
}
}

data "ec_deployment" "tags" {
data "ec_deployment" "tagdata" {
id = ec_deployment.tags.id
}

data "ec_deployments" "tagfilter" {
tags = {
"test_id" = "%s"
}
}
45 changes: 45 additions & 0 deletions ec/ecdatasource/deploymentsdatasource/expanders.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ func expandFilters(d *schema.ResourceData) (*models.SearchRequest, error) {
})
}

tags := d.Get("tags").(map[string]interface{})
var tagQueries []*models.QueryContainer
for key, value := range tags {
tagQueries = append(tagQueries,
newNestedTagQuery(key, value),
)
}
if len(tagQueries) > 0 {
queries = append(queries, &models.QueryContainer{
Bool: &models.BoolQuery{
MinimumShouldMatch: int32(len(tags)),
Should: tagQueries,
},
})
}

validResourceKinds := []string{util.Elasticsearch, util.Kibana,
util.Apm, util.EnterpriseSearch}

Expand Down Expand Up @@ -153,3 +169,32 @@ func newNestedTermQuery(path, term string, value interface{}) *models.QueryConta
},
}
}

// newNestedTagQuery returns a nested query for a metadata tag
func newNestedTagQuery(key interface{}, value interface{}) *models.QueryContainer {
return &models.QueryContainer{
Nested: &models.NestedQuery{
Path: ec.String("metadata.tags"),
Query: &models.QueryContainer{
Bool: &models.BoolQuery{
Filter: []*models.QueryContainer{
{
Term: map[string]models.TermQuery{
"metadata.tags.key": {
Value: &key,
},
},
},
{
Term: map[string]models.TermQuery{
"metadata.tags.value": {
Value: &value,
},
},
},
},
},
},
},
}
}
48 changes: 47 additions & 1 deletion ec/ecdatasource/deploymentsdatasource/expanders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package deploymentsdatasource

import (
"encoding/json"
"errors"
"testing"

Expand Down Expand Up @@ -81,7 +82,17 @@ func Test_expandFilters(t *testing.T) {
assert.NoError(t, err)
}

assert.Equal(t, tt.want, got)
jsonWant, err := json.MarshalIndent(tt.want, "", " ")
if err != nil {
t.Error("Unable to marshal wanted struct to JSON")
}

jsonGot, err := json.MarshalIndent(got, "", " ")
if err != nil {
t.Error("Unable to marshal received struct to JSON")
}

assert.Equal(t, string(jsonWant), string(jsonGot))
})
}
}
Expand All @@ -101,6 +112,9 @@ func newSampleFilters() map[string]interface{} {
return map[string]interface{}{
"name_prefix": "test",
"healthy": "true",
"tags": map[string]interface{}{
"foo": "bar",
},
"elasticsearch": []interface{}{
map[string]interface{}{
"version": "7.9.1",
Expand Down Expand Up @@ -136,6 +150,38 @@ func newTestQuery() []*models.QueryContainer {
"healthy": {Value: true},
},
},
{
Bool: &models.BoolQuery{
MinimumShouldMatch: int32(1),
Should: []*models.QueryContainer{
{
Nested: &models.NestedQuery{
Path: ec.String("metadata.tags"),
Query: &models.QueryContainer{
Bool: &models.BoolQuery{
Filter: []*models.QueryContainer{
{
Term: map[string]models.TermQuery{
"metadata.tags.key": {
Value: ec.String("foo"),
},
},
},
{
Term: map[string]models.TermQuery{
"metadata.tags.value": {
Value: ec.String("bar"),
},
},
},
},
},
},
},
},
},
},
},
{
Nested: &models.NestedQuery{
Path: ec.String("resources.elasticsearch"),
Expand Down
7 changes: 7 additions & 0 deletions ec/ecdatasource/deploymentsdatasource/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ func newSchema() map[string]*schema.Schema {
Type: schema.TypeString,
Optional: true,
},
"tags": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"return_count": {
Type: schema.TypeInt,
Computed: true,
Expand Down

0 comments on commit 1fd5515

Please sign in to comment.