Configure OpenAPI → Terraform Mapping

Brandon Croft,apiterraform

This is part of a series of notes about code generating a Terraform Provider using OpenAPI

Now that we have found all the possible REST resources that can be used, it would make sense to allow the user to specify which should be used to generate a Terraform Provider.

The tool I'm developing will initialize a config given a specification. For petstore, it looks like this:

$ tfpgen init examples/openapi/petstore.yml

api:
  scheme: bearer_token
  default_endpoint: https://api.example.com/
provider:
  name: example
specfile: examples/openapi3/petstore.yaml
output:
  Pet:
    tf_type_name_suffix: pet
    tf_type: resource
    media_type: application/json
    binding:
      create:
        path: /pet
        method: POST
      read:
        path: /pet/{petId}
        method: GET
      update:
        path: /pet/{petId}
        method: POST
      delete:
        path: /pet/{petId}
        method: DELETE
  PetFindByStatus:
    tf_type_name_suffix: pet_find_by_status
    tf_type: data_source
    media_type: application/json
    binding:
      index:
        path: /pet/findByStatus
        method: GET
  PetFindByTags:
    tf_type_name_suffix: pet_find_by_tags
    tf_type: data_source
    media_type: application/json
    binding:
      index:
        path: /pet/findByTags
        method: GET
  StoreInventory:
    tf_type_name_suffix: store_inventory
    tf_type: data_source
    media_type: application/json
    binding:
      index:
        path: /store/inventory
        method: GET
  StoreOrder:
    tf_type_name_suffix: store_order
    tf_type: data_source
    media_type: application/json
    binding:
      read:
        path: /store/order/{orderId}
        method: GET
  User:
    tf_type_name_suffix: user
    tf_type: data_source
    media_type: application/json
    binding:
      index:
        path: /user/{username}
        method: GET
  UserLogin:
    tf_type_name_suffix: user_login
    tf_type: data_source
    media_type: application/json
    binding:
      index:
        path: /user/login
        method: GET
 

tfpgen will exhaustively include data sources without regard for any actual data being there. In this case, it's prudent to remove the entire UserLogin key.

The Capital Case keys are how tfpgen initially identifies resources, discussed in these notes.

Here the user will have the opportunity to customize the terraform provider name (used as the package name as well as prefixes for each resource/data source). In the example, the resource names should be generated as example_pet in package example, with a repository name of terraform-provider-example.

The binding key gives the user some flexibility with dealing with unconventional (or un-rails-y) API paths & methods. For data source resources, it configures how the data source works: by identity or for an entire collection.

Alternatives:

You could use OpenAPI extensions to decorate a spec with Terraform provider information. I experimented with this approach but found that the location of extended attributes in the document felt unnatural. I think this is because the document is keyed by paths and multiple paths constitute a resource.

© Brandon Croft.