-
Notifications
You must be signed in to change notification settings - Fork 89
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 Traffic Filter data source #619
Merged
andrew-moldovan
merged 17 commits into
elastic:master
from
andrew-moldovan:#405-add-traffic-filter-datasource
Apr 27, 2023
Merged
Changes from 15 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
aa4baba
Adding a basic traffic filter data source that uses the ID of the fil…
andrew-moldovan dc25ccf
Pivoted to using the list api and filtering on the client for the nam…
andrew-moldovan 2a7a8bb
adding the ability to filter on region and id as well and also return…
andrew-moldovan c2e9db6
got the rules showing up as well :tada:
andrew-moldovan d2d17a9
fixing some lint
andrew-moldovan 2b5ab94
struggling with tests
andrew-moldovan 0569bb8
wow a test actually works, quick commit before I screw it up more
andrew-moldovan 5c9337c
refactored the tests and added a few more to cover the scenarios
andrew-moldovan fa561c7
and one more for matching region
andrew-moldovan 7e1e552
adding a basic acceptance test though I expect it to fail because it'…
andrew-moldovan 95ec473
refactoring the acceptance test to use region instead of id
andrew-moldovan 29ffabd
Merge branch 'master' into #405-add-traffic-filter-datasource
andrew-moldovan 7e54a92
more acc test refactoring. Creating a traffic filter resource and the…
andrew-moldovan 43cde9f
Merge branch '#405-add-traffic-filter-datasource' of https://github.c…
andrew-moldovan 943a12a
removing the testing code from the example deployment and adding docs
andrew-moldovan 30efe54
update docs link
andrew-moldovan bcf4d79
Merge branch 'master' into #405-add-traffic-filter-datasource
andrew-moldovan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 https://www.elastic.co/guide/en/cloud/current/definitions.html#TrafficFilterRulesets for the API guide | ||
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": { | ||
andrew-moldovan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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": { | ||
andrew-moldovan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although it would be better to document the actual structure here instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deliberately didn't document the actual structure here because I felt that wasn't the right choice. Why am I copy/pasting the structure from the link and writing up my own descriptions (or copying them) when that structure could change or new things added or descriptions changed? Then we'd have to remember to update them in these docs as well instead of just having people visit the one source of truth
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just re-read your comment about autogenerating these docs and I totally agree with that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because API structure changes aren't automatically reflected here. We'd have to add those fields to the provider as well.