Minimum requirements for provider CRUD and data source functions to behave properly?

I am very new to the provider SDK. I see lots of example code, but I haven’t found 1 central place that describes the minimum requirements for implementing the provider CRUD functions. I am specifically concerned with the proper way to handle what each CRUD function should do in the various scenarios of modifications to the system (i.e. what the provider is for) EXTERNAL to the terraform state. For example:

  1. What is the create function supposed to do if the resource already exists in the system? Should it throw an error or not? Should it set id to “” or not?
  2. What is the read function supposed to do if the resource no longer exists in the system? Should it throw an error or not? Should it set id to “” or not?
  3. Does the update function have to call HasChanges or can it just perform the update assuming the update function is only being called BECAUSE TF detected changes?

I guess I am looking for a boilerplate repo (using the latest sdk without using any deprecated function) with stubs for everything related to a data source and resource with comments on how to handle unexpected errors and when or when not to throw an error and when or when not to set id to a proper value OR “”.

Hi @scastria, have you had a chance to look at our scaffolding provider yet?

No, I did not know about that. I just took a look and it looks good for someone trying to get their build environment going and at the very beginning of writing a provider.

I am a little bit past that right now. I have a bunch of specific questions like the ones in my original post and a lot more.

Plus, I would like a lot more examples, like how to handle nested blocks (schemas), and more advanced stuff like that.

For example, in order to have a nested block, I see that the AWS provider uses a TypeList with MaxItems = 1. Why?

Hey @scastria,

These are all very good questions. Let me try to address them.

  1. Create should throw an error if it encounters a resource that has already been created, in most cases. Because, after all, it can’t create the resource like it wanted to. Setting the ID to "" is unnecessary in that case, Terraform shouldn’t record the resource as being created.
  2. If the Read function finds a resource that doesn’t exist anymore, it should set the ID to "" and not throw an error, in most cases. Generally, errors in Read are incredibly disruptive, because they block the user from doing anything else until the error is resolved. So you can see how throwing an error probably isn’t helpful there, as the user can’t recreate the resource with Terraform because they can’t run Terraform until the resource is recreated or they manually remove it from state. Instead, Read is supposed to reflect the current state of the resource, and if the resource is not found, it should also be not found in state. :slight_smile:
  3. The update function should only run when Terraform detects changes, but there are some caveats there. First, sometimes bugs happen. Second, sometimes what Terraform thinks of as a change, you do not think of as a change. The general pattern for writing Update functions is to assume there is a change, and to just write the current values to the API, but if you’re looking for a minimal PATCH or if your update might take multiple steps depending on what needs changing, HasChange(s) can be used to bypass unnecessary work.

I agree that what you’re looking for would be incredibly valuable, and that we should do a better job of surfacing all this information. Unfortunately, at the moment, we don’t have the resources necessary to create and keep up to date a repo of that nature. But I’ll see if we can take some steps to surface this kind of information better in a way that is sustainable for the resources we have at the moment.