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

Support the pseudo dynamic type #248

Closed
paultyng opened this issue Nov 13, 2019 · 10 comments
Closed

Support the pseudo dynamic type #248

paultyng opened this issue Nov 13, 2019 · 10 comments
Labels
enhancement New feature or request proposal terraform-plugin-framework Resolved in terraform-plugin-framework

Comments

@paultyng
Copy link
Contributor

Tracking issue for adding DynamicPseudoType type support.

@paultyng
Copy link
Contributor Author

paultyng commented Nov 14, 2019

An example that could be replaced with dynamic: https://www.terraform.io/docs/providers/aws/r/iam_policy.html#example-usage

resource "aws_iam_policy" "policy" {
  name        = "test_policy"
  path        = "/"
  description = "My test policy"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "ec2:Describe*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
EOF
}

Could be:

resource "aws_iam_policy" "policy" {
  name        = "test_policy"
  path        = "/"
  description = "My test policy"

  policy = {
    Version = "2012-10-17"
    Statement = [
      {
        Action = ["ec2:Describe*"]
        Effect = "Allow"
        Resource = "*"
      }
    ]
}

Or even:

resource "aws_iam_policy" "policy" {
  name        = "test_policy"
  path        = "/"
  description = "My test policy"

  policy = jsondecode(<<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "ec2:Describe*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
EOF
)
}

@skylerto
Copy link

I am definitely interested in this great feature! I have a few requirements out of an internal provider I'm writing to house what can be generic JSON passed to an API, similar to the generality of IAM policies! 😄

I'm currently doing the opposite of the JSON decode here, encoding HCL any type into a String for the provider to pass to an API.

@MaciejKaras
Copy link

@paultyng So I suppose we have to stick to serializing nested content via e.g. jsonencode function or some other method that creates a string. Or is there other more proper workaround that you are aware of?

Do you have any idea approximately when milestone v2.0.0 containing discussed enhancement is going to be released? I need to decide whether apply a workaround for now or just wait for new SDK release.

MaciejKaras pushed a commit to chmurakrajowa/terraform-provider-vra7 that referenced this issue Mar 2, 2020
At the moment Terraform SDK does not support nested dynamic types, which are used by vRA API.
Issue tracking development of this feature is on GitHub hashicorp/terraform-plugin-sdk#248

Workaround for this issue is added based on other providers such as AWS and IAM Policy resource https://www.terraform.io/docs/providers/aws/r/iam_policy.html#example-usage.

Support is only added for `deployment_configuration`, `resource_configuration` is untouched.
It is added to support nested structures in `deployment_configuration', especially arrays,
which are necessary for some resources to operate.

Signed-off-by: Maciej Karaś <[email protected]>
MaciejKaras pushed a commit to chmurakrajowa/terraform-provider-vra7 that referenced this issue Mar 2, 2020
At the moment Terraform SDK does not support nested dynamic types, which are used by vRA API.
Issue tracking development of this feature is on GitHub hashicorp/terraform-plugin-sdk#248

Workaround for this issue is added based on other providers such as AWS and IAM Policy resource https://www.terraform.io/docs/providers/aws/r/iam_policy.html#example-usage.

Support is only added for `deployment_configuration`, `resource_configuration` is untouched.
It is added to support nested structures in `deployment_configuration', especially arrays,
which are necessary for some resources to operate.

Signed-off-by: Maciej Karaś <[email protected]>
MaciejKaras pushed a commit to chmurakrajowa/terraform-provider-vra7 that referenced this issue Mar 2, 2020
At the moment Terraform SDK does not support nested dynamic types, which are used by vRA API.
Issue tracking development of this feature is on GitHub hashicorp/terraform-plugin-sdk#248

Workaround for this issue is added based on other providers such as AWS and IAM Policy resource https://www.terraform.io/docs/providers/aws/r/iam_policy.html#example-usage.

Support is only added for `deployment_configuration`, `resource_configuration` is untouched.
It is added to support nested structures in `deployment_configuration', especially arrays,
which are necessary for some resources to operate.

Signed-off-by: Maciej Karaś <[email protected]>
markpeek pushed a commit to vmware/terraform-provider-vra7 that referenced this issue Mar 3, 2020
* Added support for nested JSON value

At the moment Terraform SDK does not support nested dynamic types, which are used by vRA API. Issue tracking development of this feature is on GitHub hashicorp/terraform-plugin-sdk#248

Workaround for this issue is added based on other providers such as AWS and IAM Policy resource https://www.terraform.io/docs/providers/aws/r/iam_policy.html#example-usage.

Support is only added for `deployment_configuration`, `resource_configuration` is untouched.
It is added to support nested structures in `deployment_configuration', especially arrays,
which are necessary for some resources to operate.

Signed-off-by: Maciej Karaś <[email protected]>
@paultyng
Copy link
Contributor Author

paultyng commented Mar 4, 2020

@MaciejKaras we are looking to exposing this in 2.x (not 2.0), but we are probably months out for a solution for it right now if that helps you to decide, until then, yes I think the best approach is still to use typed HCL and jsonencode it to a string. To prepare for this to exist, you could have like an object_json as TypeString with the plan to eventually just add object and deprecate the _json suffixed attribute at a later date.

@paultyng paultyng removed this from the v2.0.0 milestone Apr 27, 2020
@gdavison
Copy link
Contributor

I have another usecase for this feature, also from the AWS Provider:

The resource type aws_codepipeline has an attribute, several levels of nesting down, where the type depends on the value of another attribute. It's currently implemented using a TypeMap, so we lose the ability to do validation, marking values as Sensitive, etc.

resource "aws_codepipeline" "example" {
  # ...

  stage {
   name = "Source"
   # ...
    action {
      # ...
      provider         = "GitHub"
      configuration = {
        Owner      = "lifesum-terraform"
        Repo       = "test"
        Branch     = "master"
        OAuthToken = var.github_token # This field will be settable starting in v3.0 of the AWS provider
      }
    }
  }
}

The values accepted by stage[x].action[y].configuration are controlled by stage[x].action[y].provider.

For v3.0 of the provider, we're making the whole configuration attribute as Sensitive because of the possibility of the GitHub OAuthToken being set. We're also adding a custom attribute configuration_github as an alternative, but since there are currently 29 action providers, exposing 29+ named attributes would clutter the interface.

We would still need to define the concrete types, but having them be selected by the value of provider would be much cleaner.

For example:

resource "aws_codepipeline" "example" {
  # ...

  stage {
    name = "Source"
    # ...
    action {
      # ...
      provider         = "GitHub"
      configuration = {
        owner      = "lifesum-terraform"
        repo       = "test"
        branch     = "master"
        oauth_token = var.github_token # This field would be Sensitive, the others wouldn't
      }
    }
  }

  stage {
    name = "Build"

    action {
      # ...
      provider        = "CodeBuild"
      configuration = {
        project_name = "test"
        environment_variable { # These could be structured in HCL, rather than collapsed as a string
          name  = "EXAMPLE_1"
          value = "VALUE_1"
          type  = "PLAINTEXT"
        }
        environment_variable {
          name  = "EXAMPLE_2"
          value = "example/parameter_2"
          type  = "PARAMETER_STORE"
        }
      }
    }
  }
}

@paddycarver
Copy link
Contributor

@paultyng with the introduction of terraform-plugin-go, I'm inclined to call this complete. It's not easy to use, but it's possible. Making it easier to use (by creating higher-level abstractions) I think is work that is ongoing, but that work is not specifically about exposing DynamicPseudoType.

There's an argument to be made for leaving this open until it's surfaced in the helper/schema package, but I don't know that we have any intention of doing that.

With all that being said, I'm going to close the issue out, but people should feel free to comment if they think it needs to be reopened; just make your case in the comment. :)

@skylerto
Copy link

@paddycarver awesome, glad to hear it's possible! Is there any API docs, or code blocks that you could link here as an artifact?

I haven't gotten a chance yet to play around, but so far I've seen these:

@paddycarver
Copy link
Contributor

Hey @skylerto,

Apologies, our examples are fairly lacking and the library assumes a lot of familiarity with Terraform's protocol. I can't give you a full end-to-end example, but let's see if I can give you the gist:

First, assume we're returning the schema for a resource. Let's go ahead and define that schema. In terraform-plugin-go, a schema is a map[string]tftypes.Type:

schema := map[string]tftypes.Type{
  "name": tftypes.String,
  "data": tftypes.DynamicPseudoType,
}

Then the user may specify a config like:

resource "my_resource" "foo" {
  name = "my-name"
  data = {
    "some": ["arbitrary", 123, "data", false, "here"],
  }
}

or whatever. Literally anything that can be assigned to a variable can be used as the value for data.

Then in the provider, maybe in the ApplyResourceChange RPC handler, you'll have code like this:

value, err := req.Config.Unmarshal(schema)
if err != nil {
  // return error
}
var conf map[string]tftypes.Value
err = value.As(&conf)
if err != nil {
  // return error
}

Now conf["data"] has a tftypes.Value for data. You can examine this to figure out what kind of data the user supplied. For example:

switch {
  case conf["data"].Is(tftypes.Object{}):
    var data map[string]tftypes.Value
    err := conf["data"].As(&data)
    if err != nil {
      // return error
    }
  case conf["data"].Is(tftypes.String):
    var data string
    err := conf["data"].As(&data)
    if err != nil {
        return err
    }
}

I don't know if that helps at all, but the fundamental idea is that you get the tftypes.Value with the type information from the config, and can inspect it using Value.Is and convert to Go types using Value.As.

When specifying provider-supplied data, a DynamicPseudoType just means any kind of value is acceptable in the response, just supply the value like any other, no need for special handling.

Does that help at all? Sorry, all that code was typed in a GitHub comment box, so I apologise for typos and errors.

@skylerto
Copy link

Extremely helpful @paddycarver, thank you so much!

@ghost
Copy link

ghost commented Dec 11, 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 have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 11, 2020
@bflad bflad added terraform-plugin-framework Resolved in terraform-plugin-framework and removed project/hcl2-native-sdk labels Mar 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request proposal terraform-plugin-framework Resolved in terraform-plugin-framework
Projects
None yet
Development

No branches or pull requests

7 participants