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

Resource xray sampling rules #8535

Merged
merged 19 commits into from
May 9, 2019
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ import (
"github.com/aws/aws-sdk-go/service/wafregional"
"github.com/aws/aws-sdk-go/service/worklink"
"github.com/aws/aws-sdk-go/service/workspaces"
"github.com/aws/aws-sdk-go/service/xray"
awsbase "github.com/hashicorp/aws-sdk-go-base"
"github.com/hashicorp/terraform/helper/logging"
"github.com/hashicorp/terraform/terraform"
Expand Down Expand Up @@ -276,6 +277,7 @@ type AWSClient struct {
wafregionalconn *wafregional.WAFRegional
worklinkconn *worklink.WorkLink
workspacesconn *workspaces.WorkSpaces
xrayconn *xray.XRay
}

// Client configures and returns a fully initialized AWSClient
Expand Down Expand Up @@ -447,6 +449,7 @@ func (c *Config) Client() (interface{}, error) {
wafregionalconn: wafregional.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["wafregional"])})),
worklinkconn: worklink.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["worklink"])})),
workspacesconn: workspaces.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["workspaces"])})),
xrayconn: xray.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["xray"])})),
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
}

// Handle deprecated endpoint configurations
Expand Down
2 changes: 2 additions & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ func Provider() terraform.ResourceProvider {
"aws_pinpoint_event_stream": resourceAwsPinpointEventStream(),
"aws_pinpoint_gcm_channel": resourceAwsPinpointGCMChannel(),
"aws_pinpoint_sms_channel": resourceAwsPinpointSMSChannel(),
"aws_xray_sampling_rule": resourceAwsXraySamplingRule(),

// ALBs are actually LBs because they can be type `network` or `application`
// To avoid regressions, we will add a new resource for each and they both point
Expand Down Expand Up @@ -961,6 +962,7 @@ func init() {
"wafregional",
"worklink",
"workspaces",
"xray",
}
}

Expand Down
221 changes: 221 additions & 0 deletions aws/resource_aws_xray_sampling_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/xray"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsXraySamplingRule() *schema.Resource {
return &schema.Resource{
Create: resourceAwsXraySamplingRuleCreate,
Read: resourceAwsXraySamplingRuleRead,
Update: resourceAwsXraySamplingRuleUpdate,
Delete: resourceAwsXraySamplingRuleDelete,

Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"rule_name": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 128),
},
"resource_arn": {
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Required: true,
},
"priority": {
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(1, 9999),
},
"fixed_rate": {
Copy link
Contributor Author

@dedoussis dedoussis May 6, 2019

Choose a reason for hiding this comment

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

@bflad Do you think this would require a custom validator as the validation helper does not support anything along the lines of FloatBetween?

Copy link
Contributor

Choose a reason for hiding this comment

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

It appears there are two upstream PRs for adding FloatBetween to the helper/validation package upstream:

I cannot imagine there is a specific reason why one of these is not merged, so I will followup with those maintainers to make sure the new validation function gets in. We are likely pulling in a newer version of the upstream dependency later this week anyways as part of some Terraform 0.12 work, so this problem might resolve itself shortly. I would suggest omitting any changes in this regard for now.

Type: schema.TypeFloat,
Required: true,
},
"reservoir_size": {
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntAtLeast(0),
},
"service_name": {
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(0, 64),
},
"service_type": {
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(0, 64),
},
"host": {
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(0, 64),
},
"http_method": {
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(0, 10),
},
"url_path": {
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(0, 128),
},
"version": {
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeInt,
Required: true,
ForceNew: true,
ValidateFunc: validation.IntAtLeast(1),
},
"attributes": {
Copy link
Contributor

Choose a reason for hiding this comment

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

Two notes:

  • While Terraform does not explicitly error during resource schema validation without it currently, we prefer to add the explicit Elem declaration to delineate the underlying map value type, as it likely will when a future version of the Terraform Provider SDK supports multiple map value types. I don't see an explicit Elem section in the Extending Terraform documentation section on schemas so I will make a note to ensure this gets added.
  • We can add validation for this attribute's keys and values to match the API reference via:
Elem: &schema.Schema{
	Type: schema.TypeString,
	ValidateFunc: validation.StringLenBetween(1, 32),
},
ValidateFunc: validation.StringLenBetween(1, 32),

Copy link
Contributor Author

@dedoussis dedoussis May 6, 2019

Choose a reason for hiding this comment

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

Added the Elem part - However, ValidateFunc: validation.StringLenBetween(1, 32), on the TypeMap level causes this:
Input:

...
     attributes = {
         Hello = "World"
     }
...

Output:
testing.go:568: Step 0 error: config is invalid: expected type of attributes to be string

Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringLenBetween(1, 32),
},
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceAwsXraySamplingRuleCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).xrayconn
samplingRule := &xray.SamplingRule{
RuleName: aws.String(d.Get("rule_name").(string)),
ResourceARN: aws.String(d.Get("resource_arn").(string)),
Priority: aws.Int64(int64(d.Get("priority").(int))),
FixedRate: aws.Float64(d.Get("fixed_rate").(float64)),
ReservoirSize: aws.Int64(int64(d.Get("reservoir_size").(int))),
ServiceName: aws.String(d.Get("service_name").(string)),
ServiceType: aws.String(d.Get("service_type").(string)),
Host: aws.String(d.Get("host").(string)),
HTTPMethod: aws.String(d.Get("http_method").(string)),
URLPath: aws.String(d.Get("url_path").(string)),
Version: aws.Int64(int64(d.Get("version").(int))),
}

if v, ok := d.GetOk("attributes"); ok {
samplingRule.Attributes = stringMapToPointers(v.(map[string]interface{}))
}

params := &xray.CreateSamplingRuleInput{
SamplingRule: samplingRule,
}

out, err := conn.CreateSamplingRule(params)
if err != nil {
return err
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
}

d.SetId(*out.SamplingRuleRecord.SamplingRule.RuleName)

return resourceAwsXraySamplingRuleRead(d, meta)
}

func resourceAwsXraySamplingRuleRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).xrayconn
params := &xray.GetSamplingRulesInput{}

for {
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
out, err := conn.GetSamplingRules(params)
log.Printf("[DEBUG] Retrieved Rules: %s", out.SamplingRuleRecords)
if err != nil {
d.SetId("")
return err
}
for _, samplingRuleRecord := range out.SamplingRuleRecords {
samplingRule := samplingRuleRecord.SamplingRule
if aws.StringValue(samplingRule.RuleName) == d.Id() {
d.Set("rule_name", samplingRule.RuleName)
d.Set("resource_arn", samplingRule.ResourceARN)
d.Set("priority", samplingRule.Priority)
d.Set("fixed_rate", samplingRule.FixedRate)
d.Set("reservoir_size", samplingRule.ReservoirSize)
d.Set("service_name", samplingRule.ServiceName)
d.Set("service_type", samplingRule.ServiceType)
d.Set("host", samplingRule.Host)
d.Set("http_method", samplingRule.HTTPMethod)
d.Set("url_path", samplingRule.URLPath)
d.Set("version", samplingRule.Version)
d.Set("attributes", aws.StringValueMap(samplingRule.Attributes))
d.Set("created_at", samplingRuleRecord.CreatedAt)
d.Set("modified_at", samplingRuleRecord.ModifiedAt)
d.Set("arn", samplingRule.RuleARN)
break
}
}
if out.NextToken == nil {
break
}
params.NextToken = out.NextToken
}
return nil
}

func resourceAwsXraySamplingRuleUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).xrayconn
samplingRuleUpdate := &xray.SamplingRuleUpdate{
RuleName: aws.String(d.Id()),
Priority: aws.Int64(int64(d.Get("priority").(int))),
FixedRate: aws.Float64(d.Get("fixed_rate").(float64)),
ReservoirSize: aws.Int64(int64(d.Get("reservoir_size").(int))),
ServiceName: aws.String(d.Get("service_name").(string)),
ServiceType: aws.String(d.Get("service_type").(string)),
Host: aws.String(d.Get("host").(string)),
HTTPMethod: aws.String(d.Get("http_method").(string)),
URLPath: aws.String(d.Get("url_path").(string)),
}

if d.HasChange("attributes") {
attributes := map[string]*string{}
if v, ok := d.GetOk("attributes"); ok {
if m, ok := v.(map[string]interface{}); ok {
attributes = stringMapToPointers(m)
}
}
samplingRuleUpdate.Attributes = attributes
}

params := &xray.UpdateSamplingRuleInput{
SamplingRuleUpdate: samplingRuleUpdate,
}

_, err := conn.UpdateSamplingRule(params)
if err != nil {
return err
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
}

return resourceAwsXraySamplingRuleRead(d, meta)
}

func resourceAwsXraySamplingRuleDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).xrayconn

log.Printf("[INFO] Deleting XRay Sampling Rule: %s", d.Id())

params := &xray.DeleteSamplingRuleInput{
RuleName: aws.String(d.Id()),
}
_, err := conn.DeleteSamplingRule(params)
if err != nil {
return fmt.Errorf("Error deleting XRay Sampling Rule: %s", d.Id())
dedoussis marked this conversation as resolved.
Show resolved Hide resolved
}

return nil

}
Loading