-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Traffic Filter data source (#619)
* Adding a basic traffic filter data source that uses the ID of the filter to fetch the name * Pivoted to using the list api and filtering on the client for the name of the filter we're looking for * adding the ability to filter on region and id as well and also returning more of the properties of the ruleset, though not yet complete * got the rules showing up as well 🎉 * fixing some lint * struggling with tests * wow a test actually works, quick commit before I screw it up more * refactored the tests and added a few more to cover the scenarios * and one more for matching region * adding a basic acceptance test though I expect it to fail because it's a different id * refactoring the acceptance test to use region instead of id * more acc test refactoring. Creating a traffic filter resource and then using that to query in the data source * removing the testing code from the example deployment and adding docs * update docs link
- Loading branch information
1 parent
a8bb2c1
commit cd25ecf
Showing
7 changed files
with
606 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
--- | ||
page_title: "Elastic Cloud: ec_trafficfilter" | ||
description: |- | ||
Filters for available traffic filters that match the given criteria | ||
--- | ||
|
||
# Data Source: ec_trafficfilter | ||
|
||
Use this data source to filter for an existing traffic filter that has been created via one of the provided filters. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
data "ec_trafficfilter" "name" { | ||
name = "example-filter" | ||
} | ||
data "ec_trafficfilter" "id" { | ||
id = "41d275439f884ce89359039e53eac516" | ||
} | ||
data "ec_trafficfilter" "region" { | ||
region = "us-east-1" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
* `name` (Optional) - The name of the traffic filter. Has to match exactly. | ||
* `id` (Optional) - The id of the traffic filter. Has to match exactly. | ||
* `region` (Optional) - Region where the traffic filter is. For Elastic Cloud Enterprise (ECE) installations, use `"ece-region`. | ||
|
||
## Attributes Reference | ||
See the [API guide](https://www.elastic.co/guide/en/cloud/current/definitions.html#TrafficFilterRulesets) for the available fields. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// Licensed to Elasticsearch B.V. under one or more contributor | ||
// license agreements. See the NOTICE file distributed with | ||
// this work for additional information regarding copyright | ||
// ownership. Elasticsearch B.V. licenses this file to you under | ||
// the Apache License, Version 2.0 (the "License"); you may | ||
// not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, | ||
// software distributed under the License is distributed on an | ||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
// KIND, either express or implied. See the License for the | ||
// specific language governing permissions and limitations | ||
// under the License. | ||
|
||
package acc | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
) | ||
|
||
// This test creates a resource of type traffic filter with the randomName | ||
// then it creates a data source that queries for this traffic filter by the id | ||
func TestAccDatasource_trafficfilter(t *testing.T) { | ||
datasourceName := "data.ec_trafficfilter.name" | ||
depCfg := "testdata/datasource_trafficfilter.tf" | ||
randomName := prefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) | ||
cfg := fixtureAccTrafficFilterDataSource(t, depCfg, randomName, getRegion()) | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ProtoV6ProviderFactories: testAccProviderFactory, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: cfg, | ||
PreventDiskCleanup: true, | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr(datasourceName, "rulesets.#", "1"), | ||
resource.TestCheckResourceAttr(datasourceName, "rulesets.0.name", randomName), | ||
resource.TestCheckResourceAttr(datasourceName, "rulesets.0.region", getRegion()), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func fixtureAccTrafficFilterDataSource(t *testing.T, fileName string, name string, region string) string { | ||
t.Helper() | ||
|
||
b, err := os.ReadFile(fileName) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
return fmt.Sprintf(string(b), name, region) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
resource "ec_deployment_traffic_filter" "basic" { | ||
name = "%s" | ||
region = "%s" | ||
type = "ip" | ||
|
||
rule { | ||
source = "0.0.0.0/0" | ||
} | ||
} | ||
|
||
data "ec_trafficfilter" "name" { | ||
id = ec_deployment_traffic_filter.basic.id | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
// Licensed to Elasticsearch B.V. under one or more contributor | ||
// license agreements. See the NOTICE file distributed with | ||
// this work for additional information regarding copyright | ||
// ownership. Elasticsearch B.V. licenses this file to you under | ||
// the Apache License, Version 2.0 (the "License"); you may | ||
// not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, | ||
// software distributed under the License is distributed on an | ||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
// KIND, either express or implied. See the License for the | ||
// specific language governing permissions and limitations | ||
// under the License. | ||
|
||
package trafficfilterdatasource | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/attr" | ||
"github.com/hashicorp/terraform-plugin-framework/datasource" | ||
"github.com/hashicorp/terraform-plugin-framework/diag" | ||
"github.com/hashicorp/terraform-plugin-framework/tfsdk" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
|
||
"github.com/elastic/cloud-sdk-go/pkg/api" | ||
"github.com/elastic/cloud-sdk-go/pkg/api/deploymentapi/trafficfilterapi" | ||
"github.com/elastic/cloud-sdk-go/pkg/models" | ||
"github.com/elastic/terraform-provider-ec/ec/internal" | ||
) | ||
|
||
type DataSource struct { | ||
client *api.API | ||
} | ||
|
||
var _ datasource.DataSource = &DataSource{} | ||
var _ datasource.DataSourceWithConfigure = &DataSource{} | ||
|
||
func (d *DataSource) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { | ||
return tfsdk.Schema{ | ||
Attributes: map[string]tfsdk.Attribute{ | ||
"name": { | ||
Type: types.StringType, | ||
Description: "The name we are filtering on.", | ||
Optional: true, | ||
}, | ||
"id": { | ||
Type: types.StringType, | ||
Description: "The id we are filtering on.", | ||
Optional: true, | ||
}, | ||
"region": { | ||
Type: types.StringType, | ||
Description: "The region we are filtering on.", | ||
Optional: true, | ||
}, | ||
|
||
// computed fields | ||
"rulesets": rulesetSchema(), | ||
}, | ||
}, nil | ||
} | ||
|
||
func rulesetSchema() tfsdk.Attribute { | ||
return tfsdk.Attribute{ | ||
Description: "An individual ruleset", | ||
Computed: true, | ||
Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{ | ||
"id": { | ||
Type: types.StringType, | ||
Description: "The ID of the ruleset", | ||
Computed: true, | ||
}, | ||
"name": { | ||
Type: types.StringType, | ||
Description: "The name of the ruleset.", | ||
Computed: true, | ||
}, | ||
"description": { | ||
Type: types.StringType, | ||
Description: "The description of the ruleset.", | ||
Computed: true, | ||
}, | ||
"region": { | ||
Type: types.StringType, | ||
Description: "The ruleset can be attached only to deployments in the specific region.", | ||
Computed: true, | ||
}, | ||
"include_by_default": { | ||
Type: types.BoolType, | ||
Description: "Should the ruleset be automatically included in the new deployments.", | ||
Computed: true, | ||
}, | ||
"rules": ruleSchema(), | ||
}), | ||
} | ||
} | ||
|
||
func ruleSchema() tfsdk.Attribute { | ||
return tfsdk.Attribute{ | ||
Description: "An individual rule", | ||
Computed: true, | ||
Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{ | ||
"id": { | ||
Type: types.StringType, | ||
Description: "The ID of the rule", | ||
Computed: true, | ||
}, | ||
"source": { | ||
Type: types.StringType, | ||
Description: "Allowed traffic filter source: IP address, CIDR mask, or VPC endpoint ID.", | ||
Computed: true, | ||
}, | ||
"description": { | ||
Type: types.StringType, | ||
Description: "The description of the rule.", | ||
Computed: true, | ||
}, | ||
}), | ||
} | ||
} | ||
|
||
func (d DataSource) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { | ||
// Prevent panic if the provider has not been configured. | ||
if d.client == nil { | ||
response.Diagnostics.AddError( | ||
"Unconfigured API Client", | ||
"Expected configured API client. Please report this issue to the provider developers.", | ||
) | ||
|
||
return | ||
} | ||
|
||
var newState modelV0 | ||
response.Diagnostics.Append(request.Config.Get(ctx, &newState)...) | ||
if response.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
res, err := trafficfilterapi.List(trafficfilterapi.ListParams{ | ||
API: d.client, | ||
}) | ||
|
||
if err != nil { | ||
response.Diagnostics.AddError( | ||
"Failed retrieving deployment information", | ||
fmt.Sprintf("Failed retrieving deployment information: %s", err), | ||
) | ||
return | ||
} | ||
|
||
response.Diagnostics.Append(modelToState(ctx, res, &newState)...) | ||
if response.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
// Finally, set the state | ||
response.Diagnostics.Append(response.State.Set(ctx, newState)...) | ||
} | ||
|
||
func (d *DataSource) Metadata(ctx context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { | ||
response.TypeName = request.ProviderTypeName + "_trafficfilter" | ||
} | ||
|
||
func (d *DataSource) Configure(ctx context.Context, request datasource.ConfigureRequest, response *datasource.ConfigureResponse) { | ||
client, diags := internal.ConvertProviderData(request.ProviderData) | ||
response.Diagnostics.Append(diags...) | ||
d.client = client | ||
} | ||
|
||
type modelV0 struct { | ||
Name types.String `tfsdk:"name"` | ||
Id types.String `tfsdk:"id"` | ||
Region types.String `tfsdk:"region"` | ||
Rulesets types.List `tfsdk:"rulesets"` //< rulesetModelV0 | ||
} | ||
|
||
type rulesetModelV0 struct { | ||
Id types.String `tfsdk:"id"` | ||
Name types.String `tfsdk:"name"` | ||
Description types.String `tfsdk:"description"` | ||
Region types.String `tfsdk:"region"` | ||
IncludeByDefault types.Bool `tfsdk:"include_by_default"` | ||
Rules []ruleModelV0 `tfsdk:"rules"` //< ruleModelV0 | ||
} | ||
|
||
type ruleModelV0 struct { | ||
Id types.String `tfsdk:"id"` | ||
Source types.String `tfsdk:"source"` | ||
Description types.String `tfsdk:"description"` | ||
} | ||
|
||
func modelToState(ctx context.Context, res *models.TrafficFilterRulesets, state *modelV0) diag.Diagnostics { | ||
var diags diag.Diagnostics | ||
var result = make([]rulesetModelV0, 0, len(res.Rulesets)) | ||
|
||
for _, ruleset := range res.Rulesets { | ||
if *ruleset.Name != state.Name.Value && *ruleset.ID != state.Id.Value && *ruleset.Region != state.Region.Value { | ||
continue | ||
} | ||
|
||
m := rulesetModelV0{ | ||
Name: types.String{Value: *ruleset.Name}, | ||
Id: types.String{Value: *ruleset.ID}, | ||
Description: types.String{Value: ruleset.Description}, | ||
Region: types.String{Value: *ruleset.Region}, | ||
IncludeByDefault: types.Bool{Value: *ruleset.IncludeByDefault}, | ||
} | ||
|
||
var ruleArray = make([]ruleModelV0, 0, len(ruleset.Rules)) | ||
for _, rule := range ruleset.Rules { | ||
t := ruleModelV0{ | ||
Id: types.String{Value: rule.ID}, | ||
Source: types.String{Value: rule.Source}, | ||
Description: types.String{Value: rule.Description}, | ||
} | ||
ruleArray = append(ruleArray, t) | ||
} | ||
if len(ruleArray) > 0 { | ||
m.Rules = ruleArray | ||
} | ||
|
||
result = append(result, m) | ||
} | ||
|
||
diags.Append(tfsdk.ValueFrom(ctx, result, types.ListType{ | ||
ElemType: types.ObjectType{ | ||
AttrTypes: rulesetAttrTypes(), | ||
}, | ||
}, &state.Rulesets)...) | ||
|
||
return diags | ||
} | ||
|
||
func rulesetAttrTypes() map[string]attr.Type { | ||
return rulesetSchema().Attributes.Type().(types.ListType).ElemType.(types.ObjectType).AttrTypes | ||
} | ||
|
||
func rulesetElemType() attr.Type { | ||
return rulesetSchema().Attributes.Type().(types.ListType).ElemType | ||
} | ||
|
||
func ruleAttrTypes() map[string]attr.Type { | ||
return ruleSchema().Attributes.Type().(types.ListType).ElemType.(types.ObjectType).AttrTypes | ||
} | ||
|
||
func ruleElemType() attr.Type { | ||
return ruleSchema().Attributes.Type().(types.ListType).ElemType | ||
} |
Oops, something went wrong.