-
Notifications
You must be signed in to change notification settings - Fork 55
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
Generate datasources based on OpenAPI specification #127
base: main
Are you sure you want to change the base?
Conversation
Thank you for submitting this and a BIG apology on our part for letting it languish for the last couple of weeks! I'm going to split this review between me, @louisruch and @s-christoff since it's a large PR. Love seeing the inclusion of data sources and autogen from our API spec. |
Hi @malnick, thanks for taking the time to review this. One thing that I did not add in this PR is setting the |
I like the idea of adding it to the API spec as well, there might be other wins we can get from that in tooling that leverages that spec too. I'm roping in @jefferai on this PR since it's fairly cross functional and hits on a few key areas that are under his prevue. More on this very soon as we figure out the best way to break down the review. Thank you again! |
I'm actually going to tag @jimlambrt on this since marking things sensitive is a part of the next step of eventing and probably we can have some fields automatically marked this way in openapi. That said, I also don't think it necessarily matters, as Boundary will never round trip a secret value set from Terraform back in a read. I will admit I don't have a great idea of how Sensitive is handled in TF so maybe that's not relevant? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great!
I had some general questions that I answered myself through the review. @louisruch is going to take a pass on this PR Monday, so there might be some more feedback on that review soon. Thank you again for this great contribution, both in terms of short term gains (data sources!) and the automation to make it easy for us in the future. It's a huge win for us!
resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.#", "1"), | ||
resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.%", "11"), | ||
resource.TestCheckResourceAttrSet("data.boundary_accounts.foo", "items.0.auth_method_id"), | ||
resource.TestCheckResourceAttr("data.boundary_accounts.foo", "items.0.authorized_actions.#", "6"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love the detailed checking on all resource attributes here, including authorized actions.
HI @jefferai,
This is good to know, we don't have to set anything |
Curious, any reason you based this on OpenAPI? The OpenAPI output itself is generated based on our source of truth, our proto struct and service definitions. Because the OpenAPI generation is subject to various constraints of the OpenAPI v2 spec, and may one day become a v3 spec, we use the proto definitions to build our Go API libraries and our CLI. That way we're not generating based on something that is itself generated. Edit: one of the reasons this has me concerned is that we produce OpenAPI because people ask us for it and because it might be useful for dynamic generation of web UI elements in the future but we don't really curate it. It's pretty much whatever |
Hi @jefferai, I initially tried to base the generator on the protobufs but I found it more difficult to get it working than basing the generator on the OpenAPI, I think it was mostly because everything regarding the protobufs is in I shared your fears regarding relying on the OpenAPI document, and I don't like OpenAPI in general, but since most of the work here is done by Regarding the transition from OpenAPI 2 to OpenAPI 3, I don't think it will be very difficult to update the generator which is currently quite short. |
Also regarding Boundary and Terraform, but this time to make it possible to use Boundary proxies from Terraform I opened hashicorp/terraform#29402 that may interest you. |
Everything is in We also generate the Go structs in |
Talked with the team internally -- we're going to move some of the files out of |
Hi there -- we have two paths that are being considered, and curious which is easier for you:
Thoughts? |
Hi @jefferai, sorry to answer this late, I've had a lot of work this week. I thought about both options and I don't have a strong preference for either, it seems to me that making the protobufs part of the external API would be more committing regarding backward compatibility. Since the types are already in |
You could use either! The PB files are now in the sdk module in the main branch. |
Hi everyone, sorry for the delay for getting back I've had a lot of work last weeks. I've been looking into converting the current generator from using the swagger definition to either using reflect or protoreflect but there is some details I'm not sure about. For example we extract the Do you think we should add this in the Go types as a a struct tag? |
Sorry for the lull in comms over here @remilapeyre ! We've been a little caught up in the day-to-day, but @jefferai will be reaching out again soon. |
Sorry for the delay! I think encoding the description in struct tags would likely then break whatever grpc-gateway is doing to use that description for openapi. Probably we should either:
There's an option I think is better than either but is more work:
So while I can live with (1) or (2) right now and either will work, I think long term we (being, the Boundary team, and you if interested) should push towards (3). |
Any plans to give this traction in 2024? |
@macmiranda The original author seems to have abandoned it but I think someone on the Boundary team might be picking it up soon. |
This is an experiment to see whether generating the provider based on the OpenAPI specification at https://github.com/hashicorp/boundary/blob/main/internal/gen/controller.swagger.json could work. The schema is converted from the definitions given in the document to to map[string]*schema.Schema, with two special cases: - when there is an object in an object, I convert it to a one element list as terraform-plugin-sdk v2 does not know how to express this, - when there is an opaque attribute (`map[string]interface{}`), I skip it completely as terraform-plugin-sdk does not expose `DynamicPseudoType` that would make it possible to express this attribute in native Terraform, the workaround I use in the Consul provider is to use `schema.TypeString` and `jsonencode()` but it is not ideal. Since I only worked on the datasources here I chose to skip those attributes for now. Once the schema is converted, we create the `ReadContext` function that is needed for the datasource. As it can be a bit tricky to use the Go client for each service, I chose to use directly the global *api.Client and to manually add the query params and get the raw response. While it would not be recommended for an external project to use the client this way, it fits nicely here and keep the code simple. Finally the result is written to the state, looking at the schema we generated previously to convert it. The tests are written manually so the developper can make sure that everything is working as expected even thought the code was generated and not written manually. While the conversion of the schema could be made at runtime and only one `ReadContext` function is actually needed, I find generating the code make it quite easy to review and should make it easier for contributors already accustomed to writing Terraform providers to look for errors or fork the provider for their needs. While I only worked on datasources returning lists of elements for now, I think the same approach could be used to generate datasources returning a single element and ultimately resources. This would make it very easy to keep the Terraform provider in sync with new Boundary versions, especially as the OpenAPI spec is created from the Protobuf files and the CLI is already generated on a similar principle. The code in generate_datasource.go is not very nice, but it does get the job done. I may spin it off in its own project in the future to add more feature to it. Closes hashicorp#99
This is an experiment to see whether generating the provider based on
the OpenAPI specification at https://github.com/hashicorp/boundary/blob/main/internal/gen/controller.swagger.json
could work.
The schema is converted from the definitions given in the document to
to map[string]*schema.Schema, with two special cases:
list as terraform-plugin-sdk v2 does not know how to express this,
map[string]interface{}
), Iskip it completely as terraform-plugin-sdk does not expose
DynamicPseudoType
that would make it possible to express thisattribute in native Terraform, the workaround I use in the Consul
provider is to use
schema.TypeString
andjsonencode()
but it is notideal. Since I only worked on the datasources here I chose to skip
those attributes for now.
Once the schema is converted, we create the
ReadContext
function thatis needed for the datasource. As it can be a bit tricky to use the Go
client for each service, I chose to use directly the global *api.Client
and to manually add the query params and get the raw response. While it
would not be recommended for an external project to use the client this
way, it fits nicely here and keep the code simple. Finally the result is
written to the state, looking at the schema we generated previously to
convert it.
The tests are written manually so the developper can make sure that
everything is working as expected even thought the code was generated and
not written manually.
While the conversion of the schema could be made at runtime and only
one
ReadContext
function is actually needed, I find generating the codemake it quite easy to review and should make it easier for contributors
already accustomed to writing Terraform providers to look for errors or
fork the provider for their needs.
While I only worked on datasources returning lists of elements for now,
I think the same approach could be used to generate datasources returning
a single element and ultimately resources. This would make it very easy
to keep the Terraform provider in sync with new Boundary versions,
especially as the OpenAPI spec is created from the Protobuf files and
the CLI is already generated on a similar principle.
The code in generate_datasource.go is not very nice, but it does get the
job done. I may spin it off in its own project in the future to add more
feature to it.
Closes #99