hcl2cdktf icon indicating copy to clipboard operation
hcl2cdktf copied to clipboard

Tags are rendered invalid

Open skorfmann opened this issue 4 years ago • 3 comments

The ./test.tf example renders tags like this:

        const ubuntu2 = new Instance(this, 'ubuntu2', {
            ami: "ami-0ff8a91507f77f867",
            availabilityZone: "us-east-1a",
            instanceType: "t3.nano",
            tags: [
                [{
                    name: "MyInstance2"
                }]
            ]
        });

It should be:

const ubuntu2 = new Instance(this, 'ubuntu2', {
        ami: "ami-0ff8a91507f77f867",
        availabilityZone: "us-east-1a",
        instanceType: "t3.nano",
        tags: {
          name: "MyInstance2"
        }
      })

skorfmann avatar Jul 25 '20 20:07 skorfmann

I think this is an issue when attempting to use the HCL1 parser due to this:

In Terraform v0.12 and later, the language makes a distinction between argument syntax and nested block syntax within blocks

... the JSON syntax cannot support the nested block processing mode for these arguments. This is, unfortunately, one necessary concession on the equivalence between native syntax and JSON syntax made pragmatically for compatibility with existing provider design patterns. Providers may phase out such patterns in future major releases.

I'm now having it use HCL2 by default, however I now have issues when a single block is present. Example:

resource "aws_instance" "ubuntu" {
  ami               = "ami-0ff8a91507f77f867"
  instance_type     = "t3.nano"
  availability_zone = "us-east-1a"

  network_interface {
    network_interface_id = "something"
    device_index         = 0
  }

  network_interface {
    network_interface_id = "something2"
    device_index         = 1
  }

  credit_specification {
    cpu_credits = "unlimited"
  }

  security_groups = [
    "sg-123",
    "sg-456"
  ]

  tags = {
    Name = "MyInstance"
  }
}
        const ubuntu = new Instance(this, 'ubuntu', {
            ami: "ami-0ff8a91507f77f867",
            availabilityZone: "us-east-1a",
            creditSpecification: {
                cpuCredits: "unlimited"
            },
            instanceType: "t3.nano",
            networkInterface: [
                {
                    deviceIndex: 0,
                    networkInterfaceId: "something"
                },
                {
                    deviceIndex: 1,
                    networkInterfaceId: "something2"
                }
            ],
            securityGroups: [
                "sg-123",
                "sg-456"
            ],
            tags: {
                name: "MyInstance"
            }
        });

Note the cpuCredits should be an array.

iann0036 avatar Aug 08 '20 03:08 iann0036

I took this example and converted it bare:

Generated version
        this.addOverride('locals', {
            s3OriginId: "myS3Origin"
        });

        const s3_distribution = new CloudfrontDistribution(this, 's3_distribution', {
            aliases: [
                "mysite.example.com",
                "yoursite.example.com"
            ],
            comment: "Some comment",
            defaultCacheBehavior: [{
                allowedMethods: [
                    "DELETE",
                    "GET",
                    "HEAD",
                    "OPTIONS",
                    "PATCH",
                    "POST",
                    "PUT"
                ],
                cachedMethods: [
                    "GET",
                    "HEAD"
                ],
                defaultTtl: 3600,
                forwardedValues: [{
                    cookies: [{
                        forward: "none"
                    }],
                    queryString: false
                }],
                maxTtl: 86400,
                minTtl: 0,
                targetOriginId: s3_origin_id!,
                viewerProtocolPolicy: "allow-all"
            }],
            defaultRootObject: "index.html",
            enabled: true,
            isIpv6Enabled: true,
            loggingConfig: [{
                bucket: "mylogs.s3.amazonaws.com",
                includeCookies: false,
                prefix: "myprefix"
            }],
            orderedCacheBehavior: [
                {
                    allowedMethods: [
                        "GET",
                        "HEAD",
                        "OPTIONS"
                    ],
                    cachedMethods: [
                        "GET",
                        "HEAD",
                        "OPTIONS"
                    ],
                    compress: true,
                    defaultTtl: 86400,
                    forwardedValues: [{
                        cookies: [{
                            forward: "none"
                        }],
                        headers: [
                            "Origin"
                        ],
                        queryString: false
                    }],
                    maxTtl: 31536000,
                    minTtl: 0,
                    pathPattern: "/content/immutable/*",
                    targetOriginId: s3_origin_id!,
                    viewerProtocolPolicy: "redirect-to-https"
                },
                {
                    allowedMethods: [
                        "GET",
                        "HEAD",
                        "OPTIONS"
                    ],
                    cachedMethods: [
                        "GET",
                        "HEAD"
                    ],
                    compress: true,
                    defaultTtl: 3600,
                    forwardedValues: [{
                        cookies: [{
                            forward: "none"
                        }],
                        queryString: false
                    }],
                    maxTtl: 86400,
                    minTtl: 0,
                    pathPattern: "/content/*",
                    targetOriginId: s3_origin_id!,
                    viewerProtocolPolicy: "redirect-to-https"
                }
            ],
            origin: [{
                domainName: b.bucket_regional_domain_name!,
                originId: s3_origin_id!,
                s3OriginConfig: [{
                    originAccessIdentity: "origin-access-identity/cloudfront/ABCDEFG1234567"
                }]
            }],
            priceClass: "PriceClass_200",
            restrictions: [{
                geoRestriction: [{
                    locations: [
                        "US",
                        "CA",
                        "GB",
                        "DE"
                    ],
                    restrictionType: "whitelist"
                }]
            }],
            tags: {
                Environment: "production"
            },
            viewerCertificate: [{
                cloudfrontDefaultCertificate: true
            }]
        });

        const b = new S3Bucket(this, 'b', {
            acl: "private",
            bucket: "mybucket",
            tags: {
                Name: "My bucket"
            }
        });

There were three things I had to fix manually:

  • The local issue #1
  • Attribute references should be camel cased: domainName: b.bucketRegionalDomainName!, rather than domainName: b.bucket_regional_domain_name!,
  • unreferenced variables could be omitted s3_distribution in this case. Not sure how complex. that would be.
  • bucket was declared after distribution, which made Typescript complain

Overall, just minor things and I think that this is really good already!

Here's the working version
    this.addOverride('locals', {
      s3OriginId: "myS3Origin"
  });

  const s3_origin_id = "${local.s3OriginId}"

  const b = new S3Bucket(this, 'b', {
    acl: "private",
    bucket: "mybucket",
    tags: {
        Name: "My bucket"
    }
});

  new CloudfrontDistribution(this, 's3_distribution', {
      aliases: [
          "mysite.example.com",
          "yoursite.example.com"
      ],
      comment: "Some comment",
      defaultCacheBehavior: [{
          allowedMethods: [
              "DELETE",
              "GET",
              "HEAD",
              "OPTIONS",
              "PATCH",
              "POST",
              "PUT"
          ],
          cachedMethods: [
              "GET",
              "HEAD"
          ],
          defaultTtl: 3600,
          forwardedValues: [{
              cookies: [{
                  forward: "none"
              }],
              queryString: false
          }],
          maxTtl: 86400,
          minTtl: 0,
          targetOriginId: s3_origin_id!,
          viewerProtocolPolicy: "allow-all"
      }],
      defaultRootObject: "index.html",
      enabled: true,
      isIpv6Enabled: true,
      loggingConfig: [{
          bucket: "mylogs.s3.amazonaws.com",
          includeCookies: false,
          prefix: "myprefix"
      }],
      orderedCacheBehavior: [
          {
              allowedMethods: [
                  "GET",
                  "HEAD",
                  "OPTIONS"
              ],
              cachedMethods: [
                  "GET",
                  "HEAD",
                  "OPTIONS"
              ],
              compress: true,
              defaultTtl: 86400,
              forwardedValues: [{
                  cookies: [{
                      forward: "none"
                  }],
                  headers: [
                      "Origin"
                  ],
                  queryString: false
              }],
              maxTtl: 31536000,
              minTtl: 0,
              pathPattern: "/content/immutable/*",
              targetOriginId: s3_origin_id!,
              viewerProtocolPolicy: "redirect-to-https"
          },
          {
              allowedMethods: [
                  "GET",
                  "HEAD",
                  "OPTIONS"
              ],
              cachedMethods: [
                  "GET",
                  "HEAD"
              ],
              compress: true,
              defaultTtl: 3600,
              forwardedValues: [{
                  cookies: [{
                      forward: "none"
                  }],
                  queryString: false
              }],
              maxTtl: 86400,
              minTtl: 0,
              pathPattern: "/content/*",
              targetOriginId: s3_origin_id!,
              viewerProtocolPolicy: "redirect-to-https"
          }
      ],
      origin: [{
          domainName: b.bucketRegionalDomainName!,
          originId: s3_origin_id!,
          s3OriginConfig: [{
              originAccessIdentity: "origin-access-identity/cloudfront/ABCDEFG1234567"
          }]
      }],
      priceClass: "PriceClass_200",
      restrictions: [{
          geoRestriction: [{
              locations: [
                  "US",
                  "CA",
                  "GB",
                  "DE"
              ],
              restrictionType: "whitelist"
          }]
      }],
      tags: {
          Environment: "production"
      },
      viewerCertificate: [{
          cloudfrontDefaultCertificate: true
      }]
  });

however I now have issues when a single block is present

According to the documentation this sounds like an edge case. Perhaps it's ok to ignore for the time being? I'll try to get a feeling for the occurrences of this.

Also, I'll create issues for the things I fixed manually.

skorfmann avatar Aug 08 '20 19:08 skorfmann

The schema for creditSpecification looks like this:

// On AWS instance resource
"credit_specification": {
  "type": ["list", ["object", {
    "cpu_credits": "string"
  }]],
  "description_kind": "plain",
  "computed": true
},

For the AWS Provider, there are ~ 100 occurrences of this: "type": ["list", ["object", - So, we should try to find a solution for this.

skorfmann avatar Aug 08 '20 20:08 skorfmann