Handling variable output from third party providers | plan modifiers and provider functions

First time developing a provider but I’ll try and unpack my current experience.

I’m developing a small internal provider to sit on top of an internal digital certificates API service. The core resource underlying this provider features a Required: true attribute for a CSR, due to the fact that the CSR is a hard requirement in the initial create flow.

I’m currently testing this provider in conjunction with the Akamai provider, specifically feeding in the Akamai certificate signing request data source as an input for our CSR attribute. The fun bit arrives in the formatting of the csr_rsa attribute.

Upon first calling the data source, the attribute is “technically” not formatted correctly (doesn’t contain a trailing \n escape character)

 "csr_rsa": "-----BEGIN CERTIFICATE REQUEST-----\nM....Jh+\n-----END CERTIFICATE REQUEST-----"

For whatever reason, after uploading a certificate against the Akamai akamai_cps_upload_certificate resource. This same data source will output changes, one of which being supplying the same csr_rsa attribute now with the “missing” new line character.

 "csr_rsa": "-----BEGIN CERTIFICATE REQUEST-----\nM....Jh+\n-----END CERTIFICATE REQUEST-----\n"

This discrepancy was causing my provider an issue as obviously from Terraforms perspective the CSR attribute had now changed, leading to Terraform falsely planning updates to the resource.

I started investigating how we could handle semantic equality within the plugin framework and this thread Semantic Equality, SetAttribute, and configuration changes was very helpful in helping my understanding here, one of the first things I tried was to implement a custom type.

Failing that I’ve implemented a string plan modifier, this essentially does a pem.decode on the plan and state value and sets the plan value to the state value if the bytes of each are equal. While this appears to somewhat work, it’s not quite fully solved Terraform proposing resource changes when there shouldn’t be any. I haven’t quite got to the bottom of this yet, the CSR attribute does appear to be retained from state however the plan still proposes modifying the resources.

My final attempt was to implement a provider function:

csr         = provider::my_provider::format_csr(data.akamai_cps_csr.my-csr.csr_rsa)

This just decodes and encodes the PEM string and for now has solved the problem. I suppose this is really an issue on Akamai’s side rather than the provider I’m building but it was a good issue in order to delve into the plugin framework further, I suppose I’m still wondering whether I should continue down the plan modifier path and try and get that working or whether the provider function is actually a more suitable fix in this case? This solution relies on the end user implementing the fix on a case by case basis rather than building a more resilient provider.

Is my understanding/approach here a suitable one or am I overlooking something? This has also made me think about how validation/semantic equality of attributes such as encoded certificates and signing requests might be difficult. We’d want to keep providers flexible enough to handle data that isn’t encoded exactly to official standards but still technically parses correctly. Any further thoughts/advice on this is really appreciated.

This looks like a job for a custom string type which implements basetypes.StringValuableWithSemanticEquals.

Thanks @hQnVyLRx

I was under the impression that semantic equality wouldn’t be of use to us here as we’re supplying both variations of the csr via a configuration attribute:

From the Semantic Equality, SetAttribute, and configuration changes - #2 by hQnVyLRx thread:

Semantic equality only seems to be effective when comparing values between current state → resource API, not from config → state?

Ah. I hadn’t fully understood the issue before now.

That data source is nasty.

I’d be tempted to use one of these:

  • chomp(data.akamai_cps_csr.my-csr.csr_rsa)
  • format("%s\n",chomp(data.akamai_cps_csr.my-csr.csr_rsa))

…and then open an issue on the akamai provider.

Yep, fair enough, thought it might be a “them” problem

Cheers for the assistance.