Hi! I’m working on a custom pulumi provider based ...
# pulumiverse
g
Hi! I’m working on a custom pulumi provider based on https://github.com/pulumi/pulumi-go-provider to manage resources in our internal system. The API I’m working with provides OpenAPI specs, but is not fully compliant and cannot be used with https://github.com/cloudy-sky-software/pulumi-provider-framework. I’m trying to figure out how to best handle Pulumi resource inputs/args structures so that I can leverage the OpenAPI specs: - I want to auto-generate the resource args structures from the OpenAPI specs to avoid manual coding and ensure consistency - I want to use the resource args structures so that I can generate JSON requests to the internal system API - I want the resource args structures to provide me nice resource SDK API for my Pulumi programs (so that I get nice IDE completions, type checking, etc) I’ve tried to use https://github.com/oapi-codegen/oapi-codegen to generate the Go structs from the OpenAPI specs, and it worked nice. I’ve used it as a field type in my args struct:
Copy code
type MyResourceArgs struct {
    Name string `pulumi:"name"`
    BusinessEntity schema.BusinessEntity `pulumi:"businessEntity"`
}
where
schema.BusinessEntity
is the struct generated by oapi-codegen from the OpenAPI spec and is a nested structure. However, when I generate Python SDK using
pulumi package gen-sdk --language python
, the generated args input type includes the top-level struct (generated by oapi-codegen) and annotated in Python as
pulumi.Input['_schema.BusinessEntityArgs'
which is just:
Copy code
@pulumi.input_type
class BusinessEntityArgs:
    def __init__(__self__):
        pass
so it’s missing all the nested fields. What is the preferred way to handle this scenario?
e
Is it only missing in python? If so it's probably a codegen bug, worth running
pulumi package get-schema
on the provider and seeing if that lists the nested fields.
g
I wasn’t checking other languages, as we internally write Pulumi programs only in Python. In the schema:
Copy code
{
  "name": "myprovider",
  "displayName": "yourdisplayname",
  "version": "0.1.0",
  "namespace": "example",
  "meta": {
    "moduleFormat": "(.*)"
  },
  "language": {
    "csharp": {
      "respectSchemaVersion": true
    },
    "go": {
      "generateResourceContainerTypes": true,
      "importBasePath": "github.com/example/yourdisplayname/sdk/go/yourdisplayname",
      "respectSchemaVersion": true
    },
    "nodejs": {
      "respectSchemaVersion": true
    },
    "python": {
      "pyproject": {
        "enabled": true
      },
      "respectSchemaVersion": true
    }
  },
  "config": {},
  "types": {
    "myprovider:schema:BusinessEntity": {
      "type": "object"
    }
  },
  "provider": {
    "type": "object"
  },
  "resources": {
    "myprovider:index:MyResource": {
      "properties": {
        "name": {
          "type": "string",
          "description": "Name of the resource."
        }
      },
      "type": "object",
      "required": [
        "name"
      ],
      "inputProperties": {
        "name": {
          "type": "string",
          "description": "Name of the resource."
        },
        "businessEntity": {
          "$ref": "#/types/myprovider:schema:BusinessEntity"
        }
      },
      "requiredInputs": [
        "content",
        "businessEntity"
      ]
    }
  }
}e
e
oh ok, that's schema gen isn't including the fields then. Maybe because the entity struct doesn't have the
pulumi:
tags on its fields?
g
Yes, the structs generated by oapi-codegen have json tags so they can be used for json marshalling/unmarshalling
I guess I could use https://github.com/oapi-codegen/oapi-codegen?tab=readme-ov-file#x-oapi-codegen-extra-tags---generate-arbitrary-struct-tags-to-fields and first massage my original openapi spec so that it adds pulumi tags (taking into account the names and optionality of the properties). On the other hand I think it might be quite a common scenario and it could be handled automatically by Pulumi?
e
Yeh I think if you raise an issue on the go-framework repo its not an unreasonable idea to fallback to json tags if pulumi tags are missing
g
To clarify: the go-framework = https://github.com/pulumi/pulumi-go-provider?
e
yeh
👍 1
g
I am trying to modify my original openapi spec with pulumi tags and I have a question: I have a property like:
Copy code
Addresses *[]Address `json:"addresses,omitempty"`
How should the pulumi tag look like for this? (it’s not a primitive type like string and its also an array of custom type objects)?
e
I think just
pulumi:"addresses"
👍 1
g
@echoing-dinner-19531 just a quick question to double check that it’s not PEBKAC on my side but rather a bug in `pulumi package get-schema|gen-schema`: with the following minimal repro code:
Copy code
type Organisation struct {
	Name     string `pulumi:"name"`
	Settings *[]struct {
		Name string `json:"name" pulumi:"name"`
	} `json:"settings,omitempty" pulumi:"settings"`
}

type BusinessEntityArgs struct {
	Organisation Organisation `pulumi:"organisation"`
}
when I run
pulumi package get-schema
I’m getting:
Copy code
Compiling the program ...
Finished compiling
error: rpc error: code = Unknown desc = 1 error occurred:
        * failed to get schema for 'file:index:File': could not serialize input type main.Organisation: invalid type '[]struct { Name string "json:\"name\" pulumi:\"name\"" }' on 'main.Organisation.Settings': type struct { Name string "json:\"name\" pulumi:\"name\"" } has no name
It seems it doesn’t handle
*[]struct
correctly, even though it’s tagged with
Copy code
`json:"settings,omitempty" pulumi:"settings"`
Or am I missing something?
Where the openapi spec is more or less:
Copy code
{
  "schema": {
    "components": {
      "organisation": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "x-oapi-codegen-extra-tags": {
              "pulumi": "name"
            }
          },
          "settings": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "x-oapi-codegen-extra-tags": {
                    "pulumi": "name"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
e
It might need to be a named type
g
So I would need to modify the original openapi spec and replace any “anonymous” types and promote them to named ones
e
I think so. Pulumi schema doesn't support unnamed structs, so the go framework would have to make up a name anyway.
g
Fair enough. I will also think about another approach - instead of forcing types from openapi to be supported by pulumi, I could just have the pulumi args struct to accept the generated json from openapi structs (i.e. plain string) instead and use that json as input and state in the resource