-
Notifications
You must be signed in to change notification settings - Fork 12
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
Hook up github.com/cloudy-sky-software/pulschema #213
base: main
Are you sure you want to change the base?
Conversation
3d01463
to
98c8a05
Compare
For reference, here's where the pulumi-kubernetes provider generates Pulumi schema from the Kubernetes swagger doc: |
Thanks! We have similar code in the Azure native provider as well. For the hackathon, I wanted to try out a generic solution. |
e906e34
to
3d83056
Compare
I came here through the linked issue in |
Thank you @praneetloke! Here are the OpenAPI schemas I attempted with notes on issues: // Comes out empty after loading by kin-openapi/openapi3
apigatewayV2Spec = "https://raw.githubusercontent.com/aws/aws-sdk-js/master/apis/apigatewayv2-2018-11-29.normal.json"
// Can be loaded by kin-openapi/openapi3 but pulschema fails. In genGetFunc, funcPkgCtx.propertyTypeSpec returns error
// "failed to generate property types for {Extensions:map[] OneOf:[] AnyOf:[] AllOf:[] Not:<nil> Type:<nil> Title: Format: Description:*Conditional.* This property is only present when the **field's** `action` is `added` _and_ the `added_value` is an Asana resource. This will be only the `gid` and `resource_type` of the resource when the events come from webhooks; this will be the compact representation (and can have fields expanded with [opt_fields](/docs/input-output-options)) when using the [Events](/docs/asana-events) endpoint. Enum:[] Default:<nil> Example:map[gid:12345 resource_type:user] ExternalDocs:<nil> UniqueItems:false ExclusiveMin:false ExclusiveMax:false Nullable:false ReadOnly:false WriteOnly:false AllowEmptyValue:false Deprecated:false XML:<nil> Min:<nil> Max:<nil> MultipleOf:<nil> MinLength:0 MaxLength:<nil> Pattern: MinItems:0 MaxItems:<nil> Items:<nil> Required:[] Properties:map[] MinProps:0 MaxProps:<nil> AdditionalProperties:{Has:<nil> Schema:<nil>} Discriminator:<nil>}"
asanaSpec = "https://raw.githubusercontent.com/Asana/developer-docs/master/defs/asana_oas.yaml"
// Can be loaded by kin-openapi/openapi3 but pulschema fails. In genGetFunc, funcPkgCtx.propertyTypeSpec returns error
// "failed to generate property types for {Extensions:map[] OneOf:[] AnyOf:[] AllOf:[] Not:<nil> Type: Title: Format: Description:The value of the property. Required on create and update. Enum:[] Default:<nil> Example:<nil> ExternalDocs:<nil> UniqueItems:false ExclusiveMin:false ExclusiveMax:false Nullable:false ReadOnly:false WriteOnly:false AllowEmptyValue:false Deprecated:false XML:<nil> Min:<nil> Max:<nil> MultipleOf:<nil> MinLength:0 MaxLength:<nil> Pattern: MinItems:0 MaxItems:<nil> Items:<nil> Required:[] Properties:map[] MinProps:0 MaxProps:<nil> AdditionalProperties:{Has:<nil> Schema:<nil>} Discriminator:<nil>}"
jiraSpec = "https://developer.atlassian.com/cloud/jira/platform/swagger-v3.v3.json"
// Without the x-oaiType special case, pulschema fails. In genPropertySpec, ctx.propertyTypeSpec(propName, p) returns error
// "failed to generate property types for {Extensions:map[x-oaiTypeLabel:string] OneOf:[] AnyOf:[0x14000b68e70 0x14000b68f60] AllOf:[] Not:<nil> Type:<nil> Title: Format: Description:The ID of the [Model](/docs/api-reference/models) to be used to execute this run. If a value is provided here, it will override the model associated with the assistant. If not, the model associated with the assistant will be used. Enum:[] Default:<nil> Example:gpt-4-turbo ExternalDocs:<nil> UniqueItems:false ExclusiveMin:false ExclusiveMax:false Nullable:true ReadOnly:false WriteOnly:false AllowEmptyValue:false Deprecated:false XML:<nil> Min:<nil> Max:<nil> MultipleOf:<nil> MinLength:0 MaxLength:<nil> Pattern: MinItems:0 MaxItems:<nil> Items:<nil> Required:[] Properties:map[] MinProps:0 MaxProps:<nil> AdditionalProperties:{Has:<nil> Schema:<nil>} Discriminator:<nil>}"
// Without the x-oaiType special case, can be loaded by pulschema but fails jsonschema validation of `pulumi package get-schema`
openaiSpec = "https://raw.githubusercontent.com/openai/openai-openapi/master/openapi.yaml"
// Cannot be loaded by pulschema due to the use of $ref. In GatherResourcesFromAPI, the expression
// `pathItem.Get.Responses.Status(200).Value.Content.Get(jsonMimeType)` is a nil pointer dereference. `Content` has a nil value,
// instead it has `.Extensions["schema"]["$ref"]` to specify the type.
azureResourcesSpec = "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/resources/resource-manager/Microsoft.Resources/stable/2019-08-01/resources.json" With the pulumi-go-provider integration from this PR, the provider code is simply func main() {
specUri, err := url.Parse(azureResourcesSpec)
exitIfErr(err)
m := schema.Metadata{
DisplayName: "test 1 2 3",
}
provider, err := Provider(*specUri, m)
exitIfErr(err)
err = p.RunProvider("myname", "0.1.0", provider)
exitIfErr(err)
}
// Create a new inferred provider from the given OpenAPI spec and `metadata`.
func Provider(openApiUrl url.URL, metadata schema.Metadata) (p.Provider, error) {
return openapipulschema.Wrap(p.Provider{}, openApiUrl, metadata)
} |
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.
I don't know how far you want to push this hackathon project, but I think it's very cool. If you want to keep going, I have a couple of suggestions.
I would move this out of infer
into its own top level package, since it doesn't interact with infer
in any way. Conceptually, it's a companion to infer
: infer
is a Pulumi provider from Go code. openapipulschema
is a Pulumi provider from an API spec.
Hi @praneetloke, I'm curious if you were able to reproduce my issues with loading the above schemas, or if I did something wrong here. |
AWS API Gateway How are you loading this file? As for Asana It seems that these are legit errors in their OpenAPI schema. Have a look at the Expand to see details
Atlassian Jira This one is similar to the Asana issue. Looking at the type that Expand to see details"EntityProperty": {
"additionalProperties": false,
"description": "An entity property, for more information see [Entity properties](https://developer.atlassian.com/cloud/jira/platform/jira-entity-properties/).",
"properties": {
"key": {
"description": "The key of the property. Required on create and update.",
"type": "string"
},
"value": {
<-- There should be a type property here just like `key` does.
"description": "The value of the property. Required on create and update."
}
},
"type": "object"
}, For issues where you have to patch the API spec yourself before passing it off to Lastly, when building a native provider from an OpenAPI doc, you'll want to review the conformance doc I wrote for cloud providers: https://github.com/cloudy-sky-software/cloud-provider-api-conformance. The conformance repo ensures that you have a successful conversion to Pulumi schema from an OpenAPI doc. |
As for the situation with OpenAI and its use of |
3d83056
to
b62f818
Compare
@thomas11 (or anyone else following this PR) I've spent some more time thinking about the situation with OpenAI's use of |
9301407
to
7705b07
Compare
I think it might make sense to group them somehow, the "things that create providers from some source", since there will hopefully be others. Haven't found a great name yet, though. We can postpone this until the third one comes along, if ever. |
7705b07
to
1d568a4
Compare
Thank you for your detailed analysis here, @praneetloke! I'm in two minds about this. On the one hand, yes, services should follow the spec and we should keep pulschema clean of service-specific hacks. On the other hand, in terms of ease of use, many schemas don't work out of the box and it's a high barrier to expect users to patch the schema first. And everyone who wants to use, say, OpenAPI, needs to make the same patches. Maybe a well-separated compatibility layer in pulschema, that only patches schemas to make them compliant, would be a good compromise? |
1d568a4
to
4c1670f
Compare
8a51943
to
7b44559
Compare
This commit adds a package infer/openapipulschema that uses pulschema to load an API spec and create a Pulumi schema from it. A new provider is created based on the schema plus provided metadata. Theoretically, this would allow generating the provider and schema parts for an OpenAPI-based provider, leaving only the CRUD implementations. However, I wasn't able to successfully load an OpenAPI spec with pulschema so far.
7b44559
to
ee9975d
Compare
ee9975d
to
b257cb9
Compare
@iwahbe I believe all comments are addressed. |
func (m *Metadata) PopulatePackageSpec(pkg *schema.PackageSpec) { | ||
pkg.DisplayName = m.DisplayName | ||
pkg.Description = m.Description | ||
pkg.Keywords = m.Keywords | ||
pkg.Homepage = m.Homepage | ||
pkg.Repository = m.Repository | ||
pkg.Publisher = m.Publisher | ||
pkg.LogoURL = m.LogoURL | ||
pkg.License = m.License | ||
pkg.PluginDownloadURL = m.PluginDownloadURL | ||
} | ||
|
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 change feels unnecessary. I'll leave a comment explaining how we can get around it in provider.go
.
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.
If you want to go in the direction of merging this, it needs to have documentation on [openapipulschema.Provider]
and an end to end example.
I'm having trouble thinking of a practical use case here. As far as I see, it gives a schema but no backing implementation, which means the underlying provider would need to have a full knowledge of the schema it is serving anyway.
I'm also concerned that if the schema behind the link changes, the provider will become invalid. Have you considered a design where we embed the schema instead of a link to the schema?
provider, err := openapipulschema.Provider(*specUri, m) | ||
exitIfErr(err) | ||
|
||
err = p.RunProvider("azurerm", "0.1.0", *provider) |
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.
What does consuming this provider look like. I don't see where the provider actually implements any methods beyond GetSchema
. If this provider does nothing but provide an (incorrect) schema, I don't think its a valid example.
Language: map[string]pschema.RawMessage{}, | ||
} | ||
|
||
metadata.PopulatePackageSpec(&pkg) |
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.
Instead of injecting like this, we should wrap the returned provider with schema.Wrap
.
openAPIDoc.InternalizeRefs(context.Background(), nil) | ||
|
||
pkg := pschema.PackageSpec{ | ||
Name: packageName, |
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.
Providers are not allowed to know their name until they are run, so this must be a temporary value. Can we just leave it blank?
|
||
const packageName = "openapi" | ||
|
||
func Provider(oaURL url.URL, metadata schema.Metadata) (*p.Provider, error) { |
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 needs documentation to merge. What are the constraints on oaURL
? What does the resulting provider have?
@thomas11 apologies for extremely late reply. You have an interesting idea. I'll try to keep my response brief.
You spoke my mind with that. If you would like to discuss further, I would like to invite you to start a discussion in the P.S: Also I want to let you know that, as of last night, I have open-sourced |
I think @praneetloke's release of pulumi-provider-framework answers that question - OpenAPI provider authors can use that one. I hope pulumi-provider-framework can be based on pulumi-go-provider one day. |
Nice work @praneetloke! I wish the name of the project indicated that it's specific to OpenAPI to avoid confusion with, e.g., pulumi-go-provider and pulumi-provider-boilerplate. Nevertheless, great stuff. |
This PR adds a package
openapipulschema
that uses pulschema to load an API spec and create a Pulumi schema from it. A new provideris created based on the schema plus provided metadata.
Theoretically, this would allow generating the provider and schema parts
for an OpenAPI-based provider, leaving only the CRUD implementations.
I wasn't able to successfully load an OpenAPI spec with pulschema so far due to issues in the OpenAPI specs that are discussed in this PR.
See also Handle some edge cases in various OpenAPI schemas #129 that I submitted.