How can I use cdktf in combination with the "count" attribute?

621 views Asked by At

I am using cdktf for typescript and I am facing the situation that I only want to add a resource under a given condition. To solve this problem, I found a couple of questions on SO and I figured that we might want to use count in order to solve this problem.

So I came up with this code:

    const zipBuild = new DataArchiveFile(this, 'zipBuild', {
      type: 'zip',
      sourceDir: asset.path,
      outputPath: join(asset.path, 'dist.zip'),
      excludes: ['dist.zip'], // don't zip the zip
    });
    zipBuild.addOverride("count", "${var.my_condition} ? 1 : 0");

    const build = new GoogleStorageBucketObject(this, 'build', {
      name: `gcp-fancy-bucket-name/${zipBuild.outputSha}.zip`,
      bucket: deployBucket.stringValue,
      source: zipBuild.outputPath, // <<<< This is the offending line
      timeouts: {
        create: '15m',
        update: '15m',
      },
    });
    zipBuild.addOverride("count", "${var.my_condition} ? 1 : 0");

But when I want to synthesise this code to terraform, I get an error during the terraform validate step:

Error validating cdktf {
  err: Error: Command failed: terraform validate -no-color
  
  Error: Missing resource instance key
  
    on cdk.tf.json line 122, in resource.google_storage_bucket_object.build_088E518B:
   122:         "name": "gcp-fancy-bucket-name/${data.archive_file.zipBuild_FD7BC769.output_sha}.zip",
  
  Because data.archive_file.zipBuild_FD7BC769 has "count"
  set, its attributes must be accessed on specific instances.
  
  For example, to correlate with indices of a referring resource, use:
      data.archive_file.zipBuild_FD7BC769[count.index]
  
  Error: Missing resource instance key
  
    on cdk.tf.json line 123, in resource.google_storage_bucket_object.build_088E518B:
   123:         "source": "${data.archive_file.zipBuild_FD7BC769.output_path}",
  
  Because data.archive_file.zipBuild_FD7BC769 has "count"
  set, its attributes must be accessed on specific instances.
  
  For example, to correlate with indices of a referring resource, use:
      data.archive_file.zipBuild_FD7BC769[count.index]

I checked the cdktf code of DataArchiveFile, TerraformDataSource and TerraformElement but I couldn't find a method to access zipBuild.outputPath (or another property) for an array object, rather than the single object.

Does anyone used count before in combination with cdktf and knows how to handle it?

Also I tried this, but this also failed:

    const build = new GoogleStorageBucketObject(this, 'build', {
      name: `gcp-fancy-bucket-name/${zipBuild.outputSha}.zip`,
      bucket: deployBucket.stringValue,
      source: "${" + zipBuild.fqn + ".outputPath[count.index]}",
      timeouts: {
        create: '15m',
        update: '15m',
      },
    });

because the .fqn will give me an additional set of ${}:

\\"bucket\\": \\"${${google_storage_bucket_object.build}.bucket[count.index]}\\",
3

There are 3 answers

0
unterstein On BEST ANSWER

I worked out how one array element can be accessed in this context:

The key was a combination from propertyAccess and Fn.lookup :-)

    const zipBuild = new DataArchiveFile(this, 'zipBuild', {
      type: 'zip',
      sourceDir: asset.path,
      outputPath: join(asset.path, 'dist.zip'),
      excludes: ['dist.zip'], // don't zip the zip
    });
    zipBuild.addOverride("count", "${var.my_condition} ? 1 : 0");

    const realZipBuild = propertyAccess(zipBuild.fqn, [0]);
    const zipBuildOutputPath = Fn.lookup(realZipBuild, 'output_path', '') as string;

    const build = new GoogleStorageBucketObject(this, 'build', {
      name: `gcp-fancy-bucket-name/${zipBuild.outputSha}.zip`,
      bucket: deployBucket.stringValue,
      source: zipBuildOutputPath,
      timeouts: {
        create: '15m',
        update: '15m',
      },
    });
    zipBuild.addOverride("count", "${var.my_condition} ? 1 : 0");
2
Kerry Wilson On

Given that conditionals and looping are one of the primary reasons to use cdktf, my suggestion would be to use standard Terraform for your project.

0
Navdeep Duvedi On

I have worked with cdktf and count using typescript. The best way i was able to tackle the count was to use interpolation to get desired value. Example

 new VolumeAttachment(this,"example-disk-attachment",{
  deviceName: "/dev/sdh",
  volumeId : `\${element(aws_ebs_volume.example-disk.*.id, count.index)}`,
  instanceId: `\${element(aws_instance.example-machine.*.id, count.index)}`,
  dependsOn : [ec2Instance,exampleVolume],
  count: networkCount
})

This is just an example how i used interpolation with terraform cdk to make count work. I can share more context to this if you want as it worked perfectly fine for me.