iann0036 / hcl2cdktf

Converts HCL to Terraform CDK
MIT License
40 stars 4 forks source link

Tags are rendered invalid #4

Open skorfmann opened 4 years ago

skorfmann commented 4 years ago

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"
        }
      })
iann0036 commented 4 years ago

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.

skorfmann commented 4 years ago

I took this example and converted it bare:

Generated version ```ts 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:

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

Here's the working version ```ts 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 commented 4 years ago

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.