David SHainidze
David SHainidze

Reputation: 237

How can I read JSON data in a variable with type of `types.Dynamic`?

I am writing a Custom Terraform Provider for Ansible Forms using the Terraform plugin framework (GitHub - hashicorp/terraform-plugin-framework: A next-generation framework for building Terraform providers. v1.8.0). How can I read JSON string in a field with type types.Dynamic? The JSON string itself contains a map where values types are different.

Here is my DS model:

type JobDataSourceModel struct {
    CxProfileName types.String  `tfsdk:"cx_profile_name"`
    ...
    Extravars     types.Dynamic `tfsdk:"extravars"`
    ...
}

Here is the Schema() method:

func (d *JobDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            ...
            "extravars": schema.DynamicAttribute{
                MarkdownDescription: "",
                Computed:            true,
            },
            ...
        },
    }
}

The Read() method:

func (d *JobDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
    var data JobDataSourceModel
    ...
    data.Extravars = types.DynamicValue(restInfo.Data.Extravars)
    ...
}

Data returned by the Ansible Forms API is given below. The extravars field is a JSON string in the API response. I am converting a value of extravars into a map. Map values has diff types such as list, str, and boolean. That's why I want to use types.Dynamic.

{
    "status": "success",
    "message": "job ran successfully",
    "data": {
        "id": 86,
        "form": "Demo Form Ansible No input",
        "target": "Demo Form Ansible No input",
        "status": "success",
        "start": "2024-05-02T15:35:16.000Z",
        "end": "2024-05-02T15:35:18.000Z",
        "user": "admin",
        "user_type": "local",
        "job_type": "ansible",
        "extravars": "{\"name\":\"vm1\",\"region\":\"myregion\",\"opco\":\"myopco\",\"svm_name\":\"mysvm_name\",\"exposure\":\"myexposure\",\"env\":\"myenv\",\"dataclass\":\"mydataclass\",\"share_name\":\"myshare_name\",\"accountid\":\"myaccountid\",\"size\":\"mysize\",\"protection_required\":\"myprotection_required\",\"ansibleforms_user\":{\"username\":\"admin\",\"id\":1,\"type\":\"local\",\"groups\":[\"local/admins\"],\"roles\":[\"public\",\"admin\"]},\"__playbook__\":\"dummy.yaml\",\"__inventory__\":\"\",\"__credentials__\":{\"vcenterCredentials\":\"VCENTER\"}}",
        "credentials": "{\"vcenterCredentials\":\"VCENTER\"}",
        "notifications": "{}",
        "approval": null,
        "step": null,
        "parent_id": null,
        "subjobs": null,
        "no_of_records": 45,
        "counter": 8,
        "output": "<span class='has-text-warning'>[WARNING]: No inventory was parsed, only implicit localhost is available</span> <span class='tag is-info is-light'>2024-05-02 15:35:17</span>\r\n<span class='has-text-warning'>[WARNING]: provided hosts list is empty, only localhost is available. Note that</span> <span class='tag is-info is-light'>2024-05-02 15:35:17</span>\r\n<span class='has-text-warning'>the implicit localhost does not match 'all'</span>\r\n<span class='has-text-warning'>[WARNING]: Found variable using reserved name: name</span> <span class='tag is-info is-light'>2024-05-02 15:35:17</span>\r\n\n<span class='has-text-weight-bold'>PLAY [This is a hello-world example] *******************************************</span> <span class='tag is-info is-light'>2024-05-02 15:35:17</span>\r\n\r\n<span class='has-text-weight-bold'>TASK [Gathering Facts] *********************************************************</span>\r\n<span class='has-text-success'>ok: [localhost]</span> <span class='tag is-info is-light'>2024-05-02 15:35:18</span>\r\n\r\n<span class='has-text-weight-bold'>TASK [Output 'Welcome'.] *******************************************************</span>\r\n<span class='has-text-success'>ok: [localhost] => </span> <span class='tag is-info is-light'>2024-05-02 15:35:18</span>\r\n<span class='has-text-success'>  msg: Hi there and welcome to ansible</span>\r\n\r\n<span class='has-text-weight-bold'>PLAY RECAP *********************************************************************</span>\r\n<span class=''>localhost                  : <span class='tag is-success'>ok=2</span>    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0</span>\r\n<span class='has-text-success'>ok: [Playbook finished] with status (0)</span> <span class='tag is-info is-light'>2024-05-02 15:35:18</span>"
    }
}

I've tried doing that with the code abov, but it does not work.

Upvotes: 1

Views: 105

Answers (1)

Helder Sepulveda
Helder Sepulveda

Reputation: 17574

Looking for example of terraform resources with similar json input, found this is one:

resource "aws_api_gateway_stage" "deploy" {
  depends_on = [
    aws_api_gateway_account.demo
  ]
  deployment_id = aws_api_gateway_deployment.deploy.id
  rest_api_id   = aws_api_gateway_rest_api.x.id
  stage_name    = "test"
  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.logs.arn
    format          = "{ \"requestId\":\"$context.requestId\" }"
  }
}

see the format there is json data and in the code for that:

https://github.com/hashicorp/terraform-provider-aws/blob/main/internal/service/apigateway/stage.go#L56-L73

Schema: map[string]*schema.Schema{
    "access_log_settings": {
        Type:     schema.TypeList,
        MaxItems: 1,
        Optional: true,
        Elem: &schema.Resource{
            Schema: map[string]*schema.Schema{
                "destination_arn": {
                    Type:         schema.TypeString,
                    Required:     true,
                    ValidateFunc: verify.ValidARN,
                },
                "format": {
                    Type:     schema.TypeString,
                    Required: true,
                },
            },
        },
    },
    ...

... and if you need to read something from that json string use json.Unmarshal there are a lot of examples, here is one: https://go.dev/play/p/zdMq5_ex8G

Upvotes: 0

Related Questions