New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Config
to the resource.ReadRequest
#878
Comments
Hi @tmatilai 👋 Thank you for raising this feature request. The implementation reason that The comments in the protocol definition mention some of the design reasoning for this:
Since that is a design problem that would need to be accepted as a design tradeoff (or somehow solved) upstream in Terraform, then implemented in the protocol, there is nothing that can be implemented in terraform-plugin-go or this Go module for the given proposal at the moment. For the situation you mention though, I believe we may need some additional information before we can provide guidance. Is the optional and computed attribute returned from the API? If not, then this is not a situation that managed resource refresh (resource |
Hi Brian, thanks a lot for the detailed response! Even though I've been using Terraform for a very long time, unfortunately I've never studied the details of the internals. But learning bit by bit now. 🙂
Yeah sorry, I should have included more concrete example. I've seen this need already in a couple of places, but now it came with the TFE provider. Most of the resources include Almost all of the resources in the TFE provider still use the SDKv2, and now I came to this when trying to implement a new resource and data source using the plugin framework. And turns out that the existing implementation also suffers from the same issue. Indeed Any suggestions highly appreciated. But I understand if the protocol specification doesn't allow perfect solution for this. |
We also face an issue were we need access to the
The provider will create this resource and explicitly ask the API to include The problems start when you use import to import the resource with id 42 into the state. The import has no way of knowing which attributes to include, so when At the moment, the only way out of this situation is to manually edit the state and set the required attributes to some (incorrect) non-null value and do a refresh. I really see no way to implement this correctly in the provider other than requiring the user to explicitly list the required attributes at several locations, which would result in a very poor experience. |
Hi @tmatilai and @papegaaij 👋 If the resource implements the In the case where the API selectively returns information, my recommendation would be to set all those attributes to optional and computed, and always store/refresh all values. This will ensure that no matter whether the resource is being imported (no state) or remotely drifted (now incorrect state), Terraform will always be able to plan value differences from the given resource configuration. If you have further questions about either of these scenarios, I would encourage posting a new topic in the Terraform Plugin Development section of HashiCorp Discuss, where there are more developers asking and answering provider development questions similar to these. 👍 |
Hi @bflad, Access to the provider-level data is no good for our usecase. The required attributes can differ per resource. Requesting all attributes will require massive permission sets for the Terraform provider for all resources provided by the API. Making it totally impossible to give fine grained permissions. Also, some of these attributes are very heavy to compute, leave audit trails when accessed and/or trigger webhooks. Accessing all attributes will result in very poor performance, massive audit trail flooding, triggering webhooks all over the place, and its very likely to trigger alerts in SIEMs. This is nowhere near acceptable for our API. Also, Optional and Computed attributes cause major issues with drift if these attributes are not fixed on the external resource, and many or our attributes are dynamic (containing live computed data, statistics or changing data sets). Including all these attributes will result in plans that will never be stable. By selectively enabling only 1 or 2 attributes, the chances of drift are reduced a lot. |
Hi again, @papegaaij. That additional context is helpful. The maintainers of this project do not know details of your particular API so we generally have to make broad assumptions using our experiences with other APIs and provider design in the industry. I think, unfortunately, to be able to make real recommendations here, we would need to know even more details about your particular situation/API, the conceptual data structures and relationships of resources within your API, and how you are expecting practitioners to use Terraform to declaratively interact with the API. If there is public documentation for what you are working with, that would be beneficial for us to understand your situation and help better. Offhandedly though (again without full context), this now sounds like you could be in a situation where the resource should be split up further for each "part"/"kind" of resource configuration that results in the differing data from the API. For example, the |
Hi @bflad , The provider I'm working on is for Topicus KeyHub, our IAM solution. You can find the (skeleton of) the documentation at https://registry.terraform.io/providers/topicuskeyhub/keyhub/latest/docs . As the provider is still under heavy development, the documentation is just what's produced by the generator. The provider is generated from our OpenAPI specification using a generator we developed ourselves. You can find the specification here https://github.com/topicuskeyhub/sdk-go/blob/main/openapi.json . A factor that makes developing a terraform provider for our API more difficult is that many of our resources do not allow clients to update or delete, only create and read. This stems from our principle that changes to permissions should always be traceable to a person. Creating a new permission is fine, but updating it is not. A simple example is creating a group. The provider can create a new group, but it cannot update it. Also, changes to memberships can only be done by an authorized manager of that group. The terraform provider can however create a new group with a predefined set of members. This is one of these optional attributes. When set, the provider will create the group with the configured accounts, and will verify the accounts of that groups by reading them. This does however require permissions. If you do not want the provider to manage the accounts of the group, you do not need to give the provider these permissions. The accounts must be specified as part of the resource, because the creation requires them all in a single bundle. Given the situation that the provider manages the accounts for a specific group, the provider must fetch the accounts for that group when reading. However, when the user uses import to import the state for that group, the provider has no way of knowing whether it must fetch these accounts or not. At the moment, group has 3 of these types of attributes, but we will very likely be adding more. Another category of attributes are computed (or gathered) statistics. These can change at every request and are therefore not very useful to use in resources, but can be useful for troubleshooting and output. At the moment, I only see one viable solution for import: require the user to declare which attributes are required in the config (in addition to actually providing the contents of the writable attributes). We already have an attribute for this, called |
Module version
Use-cases
Allow users to (optionally) specify a default value for a common argument in many resources and data sources.
I.e., the resources and data sources have optional and computed
foo
attribute. If not specified, the value from the provider attributefoo
would be used. If even that is not specified, fail the run.For example:
Attempted Solutions
I have thought and tried different solutions, but all have their issues. I might of course miss something here.
foo
is configured in the provider and changes, updating the resource will lead to theProvider produced inconsistent result after apply
error on other computed fields. In a single resource it would be fine to set all to unknown in theModifyPlan()
, but no idea how to iterate them in a generic way if the same function is used in many resources.Create()
works. But inRead()
there is no access to theConfig
and theState
has the old value, so if the value comes from the provider, any changes are not detected. Another downside is that in diffs the value is always(known after apply)
.Read()
seems like the only option, but there it works fine.Proposal
Add
Config
to theresource.ReadRequest
struct to be accessible in the resource'sRead()
function.Of course if there are other ways to implement this, nice. 🙂
Some way for setting all the computed,
null
configured attributes back to unknown at least would be fine.The text was updated successfully, but these errors were encountered: