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

Implement data aws_pricing_product #5057

Merged
merged 5 commits into from
Jul 4, 2018

Conversation

julienduchesne
Copy link
Contributor

Fixes #5009

Changes proposed in this pull request:

Output from acceptance testing:

make testacc TESTARGS='-run=TestAccDataSourceAwsPricingProduct'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./... -v -run=TestAccDataSourceAwsPricingProduct -timeout 120m
?       github.com/terraform-providers/terraform-provider-aws   [no test files]
=== RUN   TestAccDataSourceAwsPricingProduct_ec2
--- PASS: TestAccDataSourceAwsPricingProduct_ec2 (12.48s)
=== RUN   TestAccDataSourceAwsPricingProduct_redshift
--- PASS: TestAccDataSourceAwsPricingProduct_redshift (11.98s)
PASS
ok      github.com/terraform-providers/terraform-provider-aws/aws       24.467s

@ghost ghost added size/XXL Managed by automation to categorize the size of a PR. dependencies Used to indicate dependency changes. labels Jul 3, 2018
@ghost ghost added size/XXL Managed by automation to categorize the size of a PR. dependencies Used to indicate dependency changes. labels Jul 3, 2018
@bflad bflad added the service/pricing Issues and PRs that pertain to the pricing service. label Jul 3, 2018
@bflad
Copy link
Contributor

bflad commented Jul 3, 2018

Hi @julienduchesne, thanks for submitting this data source! I did want to touch base briefly about the below:

AWS returns a large json result. To parse through the result, I added the gjson library (https://github.com/tidwall/gjson), this is accessible through the json_query attribute. I understand that you may want to reduce dependencies but filtering through json results is actually quite complex and I have not seen anywhere else in the provider where it is done. I am open to suggestions on this.

We are just starting the process of writing up Terraform provider development best practices documentation and this is likely an item that would appear there. 😄

At first blush, this seems like it belongs in its own separate data source and most likely in its own provider, rather than something to implement piecemeal per resource and data source everywhere. For example, from an operator perspective, this might be useful (calling the new provider json and the data source json_query for illustrative purposes):

data "aws_pricing_product" "example" {
  service_code = "AmazonRedshift"

  filters = [
    {
      field = "instanceType"
      value = "ds1.xlarge"
    },
    {
      field = "location"
      value = "US East (N. Virginia)"
    },
  ]
}

data "json_query" "example" {
  json = "${data.aws_pricing_product.example.json}"
  query = "terms.OnDemand.*.priceDimensions.*.pricePerUnit.USD"
}

output "example" {
  values = "${data.json_query.example.value}"
}

I cannot guarantee that HashiCorp would necessarily be willing to maintain this as a new provider, but if it makes sense from a generic sense, I can reach out and gather opinions on hosting it as a community provider as part of the Terraform Provider Development Program.

There is also an existing community provider implementation that might be able to help here: https://github.com/EvilSuperstars/terraform-provider-jsondecode

Better news though is that while the Terraform 0.12 preview blog post did not specifically mention it, Terraform 0.12 will be able to support a jsondecode() built-in function due to the strong typing being implemented throughout Terraform core. In that case, I believe it should be possible to do something like:

data "aws_pricing_product" "example" {
  service_code = "AmazonRedshift"

  filters = [
    {
      field = "instanceType"
      value = "ds1.xlarge"
    },
    {
      field = "location"
      value = "US East (N. Virginia)"
    },
  ]
}

# Potential Terraform 0.12 syntax - may change during implementation
# Also, not sure about the exact attribute reference architecture myself :)
output "example" {
  values = jsondecode(data.json_query.example.value).terms.OnDemand.*.priceDimensions.*.pricePerUnit.USD
}

That feature can be tracked upstream at: hashicorp/terraform#10363

With all that said, we likely would not want to merge in the extra dependency or json_query handling in this data source as it is better suited with a more generic solution. If you can remove those out of this pull request, that will greatly speed up getting this merged. 👍

@bflad bflad added waiting-response Maintainers are waiting on response from community or contributor. new-data-source Introduces a new data source. labels Jul 3, 2018
@ghost ghost added size/XL Managed by automation to categorize the size of a PR. dependencies Used to indicate dependency changes. and removed size/XXL Managed by automation to categorize the size of a PR. labels Jul 3, 2018
@ghost ghost added size/L Managed by automation to categorize the size of a PR. and removed size/XL Managed by automation to categorize the size of a PR. dependencies Used to indicate dependency changes. labels Jul 3, 2018
@julienduchesne
Copy link
Contributor Author

julienduchesne commented Jul 3, 2018

Alright, here you go

make testacc TESTARGS='-run=TestAccDataSourceAwsPricingProduct'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./... -v -run=TestAccDataSourceAwsPricingProduct -timeout 120m
?       github.com/terraform-providers/terraform-provider-aws   [no test files]
=== RUN   TestAccDataSourceAwsPricingProduct_ec2
--- PASS: TestAccDataSourceAwsPricingProduct_ec2 (14.45s)
=== RUN   TestAccDataSourceAwsPricingProduct_redshift
--- PASS: TestAccDataSourceAwsPricingProduct_redshift (14.05s)
PASS
ok      github.com/terraform-providers/terraform-provider-aws/aws       28.508s

Let me know if anything else is not OK

@bflad bflad removed the waiting-response Maintainers are waiting on response from community or contributor. label Jul 4, 2018
Copy link
Contributor

@bflad bflad left a comment

Choose a reason for hiding this comment

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

This is looking pretty good 👍 A few minor things below and this should be ready to ship.

package aws

import (
"log"
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor nitpick: The Go imports seem to be a little off formatting wise. The stdlib imports should be grouped and alphabetically sorted at the top, a blank line, then external imports grouped and alphabetically sorted.

We tend to prefer using goimports for managing these consistently (and automatically) everywhere 👍

)

const (
awsPricingTermMatch = "TERM_MATCH"
Copy link
Contributor

Choose a reason for hiding this comment

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

We should prefer to use the available SDK constant: pricing.FilterTypeTermMatch

return fmt.Errorf("Error reading pricing of products: %s", err)
}

if err = verifyProductsPriceListLength(resp.PriceList); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor nitpick: given this function is not being used elsewhere and not explicitly unit tested, we can remove the indirection and just include the logic inline here.

)

func TestAccDataSourceAwsPricingProduct_ec2(t *testing.T) {
os.Setenv("AWS_DEFAULT_REGION", "us-east-1")
Copy link
Contributor

Choose a reason for hiding this comment

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

We should save the original value and reset it after completion or this could break other tests:

	oldRegion := os.Getenv("AWS_DEFAULT_REGION")
	os.Setenv("AWS_DEFAULT_REGION", "us-east-1")
	defer os.Setenv("AWS_DEFAULT_REGION", oldRegion)

The same should be applied to the other acceptance test. Admittedly, we need to remove using environment variables for this purpose. 🙁

## Argument Reference

* `service_code` - (Required) The code of the service. Available service codes can be fetched using the DescribeServices pricing API call.
* `filters` - (Required) A list of filters. Passed directly to the API (see GetProducts API reference). These filters must describe a single product, this resource will fail if more than one product is returned by the API.
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to describe the filters nested fields as well, e.g.

### filters

* `field` (Required) The attribute name that you want to filter on.
* `value` (Required) The attribute value that you want to filter on.

---
layout: "aws"
page_title: "AWS: aws_pricing_product"
sidebar_current: "docs-aws-datasource-pricing-product"
Copy link
Contributor

Choose a reason for hiding this comment

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

This page needs a sidebar link added to website/aws.erb

@bflad bflad added the waiting-response Maintainers are waiting on response from community or contributor. label Jul 4, 2018
@ghost ghost added the size/L Managed by automation to categorize the size of a PR. label Jul 4, 2018
@ghost ghost added the size/L Managed by automation to categorize the size of a PR. label Jul 4, 2018
@bflad bflad removed the waiting-response Maintainers are waiting on response from community or contributor. label Jul 4, 2018
@bflad bflad added this to the v1.26.0 milestone Jul 4, 2018
@bflad bflad merged commit 1d729c1 into hashicorp:master Jul 4, 2018
@bflad
Copy link
Contributor

bflad commented Jul 4, 2018

Looks great, @julienduchesne! 🚀

make testacc TEST=./aws TESTARGS='-run=TestAccDataSourceAwsPricingProduct'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./aws -v -run=TestAccDataSourceAwsPricingProduct -timeout 120m
=== RUN   TestAccDataSourceAwsPricingProduct_ec2
--- PASS: TestAccDataSourceAwsPricingProduct_ec2 (6.03s)
=== RUN   TestAccDataSourceAwsPricingProduct_redshift
--- PASS: TestAccDataSourceAwsPricingProduct_redshift (4.86s)
PASS
ok  	github.com/terraform-providers/terraform-provider-aws/aws	10.928s

@bflad bflad mentioned this pull request Jul 4, 2018
bflad added a commit that referenced this pull request Jul 4, 2018
@julienduchesne julienduchesne deleted the aws-pricing branch July 4, 2018 10:14
@bflad
Copy link
Contributor

bflad commented Jul 4, 2018

This has been released in version 1.26.0 of the AWS provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

@tomelliff
Copy link
Contributor

I couldn't quite get the pre 0.12 proposed syntax working. The following seems to work okay though:

variable "instance_type" {}

provider "aws" {
  alias  = "us-east-1"
  region = "us-east-1"
}

data "aws_region" "current" {}

data "aws_pricing_product" "example" {
  provider = aws.us-east-1

  service_code = "AmazonEC2"

  filters {
    field = "capacitystatus"
    value = "Used"
  }

  filters {
    field = "instanceType"
    value = var.instance_type
  }

  filters {
    field = "operatingSystem"
    value = "Linux"
  }

  filters {
    field = "location"
    value = data.aws_region.current.description
  }

  filters {
    field = "preInstalledSw"
    value = "NA"
  }

  filters {
    field = "licenseModel"
    value = "No License required"
  }

  filters {
    field = "tenancy"
    value = "Shared"
  }
}

output "on_demand_price" {
  value = tonumber(values(values(jsondecode(data.aws_pricing_product.example.result).terms.OnDemand)[0].priceDimensions)[0].pricePerUnit.USD)
}

Not sure if there's a better/cleaner way to be getting at the relevant data though?

Would it be worth adding this as an example to the resource's documentation?

@ghost
Copy link

ghost commented Feb 10, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks!

@ghost ghost locked and limited conversation to collaborators Feb 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
new-data-source Introduces a new data source. service/pricing Issues and PRs that pertain to the pricing service. size/L Managed by automation to categorize the size of a PR.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

data aws_pricing_instance
3 participants