Home

Awesome

swagger-k8s-crd-codegen

This naive proof-of-concept reads a swagger.yml to produce Kubernetes CRDs of the specified models.

NOTE: This generator only parses model definitions, and does not parse, examine, or utilize any paths within your application.

Motivation

Swagger is a tool for documenting interactions that will take place in an API using OpenAPI. Kubernetes is a container orchestration environment that allows for extending their API using CustomResourceDefinitions.

CustomResourceDefinitions (CRDs) are defined using the same OpenAPI language used by Swagger.

By specifying a few additional annotations, we can generate a Kubernetes CRD from the same Swagger spec.

Running in Python

Install dependencies:

$ pip install --user -r requirements.txt

Run the Python script:

$ python ./swagger-k8s-crd-codegen.py

Running in Docker

Build the Docker image:

$ docker build -t bodom0015/swagger-k8s-crd-codegen . 

Run the Docker image:

$ docker run -it --rm -v $(pwd)/target/:/app/target bodom0015/swagger-k8s-crd-codegen
Writing target/workbenchuserapps.crd.yml

Usage

This parser looks for special attributes in your model definition. Please define the following:

KeyDefinitionExample
x-groupNamegroup name to use for generated CRDndslabs.org
x-versionversion name to use for generated CRDv1
x-singularname for a single CRD of this typeworkbenchuserapp
x-pluralname for multiple CRD of this typeworkbenchuserapps
x-kindCamelCase kind for this CRDWorkbenchUserApp
x-scopeNamespaced, else Cluster will share to all namespacesNamespaced or Cluster
x-shortNameslist of shorter string aliases for this CRD(See below)

Defining Short Names

Short names allow you to use kubectl get <shortname> to list the custom resources on the cluster.

Short names for a CRD can be defined as a list, for example:

x-shortNames:
  - workbenchapp
  - workbenchapps
  - wbuserapp
  - wbuserapps
  - userapp
  - userapps
  - wbapp
  - wbapps
  - app
  - apps

This would enable the use of kubectl get workbenchapp or kubectl get userapp or kubectl get apps, etc.

Full Example

Sample Input (swagger.yml):

swagger: '2.0'
info:
  title: Fake Example API
  description: Sample API for the swagger-k8s-crd-codegen
  version: 0.0.1
host: localhost:5000
basePath: /api

produces:
  - application/json
consumes:
  - application/json

# NOTE: paths are ignored by swagger-k8s-crd-codegen
paths:
  /hello:
    get:
      description: |
        Say hello
      responses:
        '200':
          description: OK
          schema:
            type: string

definitions:
  UserApp:
    x-groupName: "ndslabs.org"
    x-version: "v1"
    x-plural: "workbenchuserapps"
    x-singular: "workbenchuserapp"
    x-kind: "WorkbenchUserApp"
    x-scope: "Namespaced"
    x-shortNames:
      - workbenchapp
      - workbenchapps
      - wbuserapp
      - wbuserapps
      - userapp
      - userapps
      - wbapp
      - wbapps
      - app
      - apps
    type: object
    properties:
      hello:
        type: string
      world:
        type: string

Using the commands above, run the script using either Python or Docker.

This should produce the output below (e.g. target/workbenchuserapps.crd.yaml):


## This file was generated by swagger-k8s-crd-codegen.
## Any manual changes to this file may be overwritten.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  # name must match the spec fields below, and be in the form: <plural>.<group>
  name: workbenchuserapps.ndslabs.org
spec:
  # group name to use for REST API: /apis/<group>/<version>
  group: ndslabs.org
  # list of versions supported by this CustomResourceDefinition
  versions:
    - name: v1
      # Each version can be enabled/disabled by Served flag.
      served: true
      # One and only one version must be marked as the storage version.
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                hello:
                  type: string
                world:
                  type: string
              type: object



  # either Namespaced or Cluster
  scope: Namespaced
  names:
    # plural name to be used in the URL: /apis/<group>/<version>/<plural>
    plural: workbenchuserapps
    # singular name to be used as an alias on the CLI and for display
    singular: workbenchuserapp
    # kind is normally the CamelCased singular type. Your resource manifests use this.
    kind: WorkbenchUserApp
    # shortNames allow shorter string to match your resource on the CLI
    shortNames:
      - workbenchapp
      - workbenchapps
      - wbuserapp
      - wbuserapps
      - userapp
      - userapps
      - wbapp
      - wbapps
      - app
      - apps

Using kubectl, add this new definition to your cluster:

$ kubectl apply -f target/workbenchuserapps.crd.yml 
customresourcedefinition.apiextensions.k8s.io/workbenchuserapps.ndslabs.org created

Create a new resource using the custom definition (e.g. app1.userapp.yml):

kind: WorkbenchUserApp
metadata:
  name: my-user-app-number-1
spec:
  hello: it
  world: works

Note that our spec here must match up with that of the openAPIV3Schema defined above.

Create this new resource on your cluster:

$ kubectl apply -f app1.userapp.yml

NOTE: you can use use any of the shortname aliases defined to list/view/describe your resource.

List your created resources:

$ kubectl get workbenchuserapps
NAME                   AGE
my-user-app-number-1   62m

View details about a particular resource

$ kubectl describe userapp my-user-app-number-1
Name:         my-user-app-number-1
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  ndslabs.org/v1
Kind:         WorkbenchUserApp
Metadata:
  Creation Timestamp:  2021-10-21T18:41:31Z
  Generation:          1
  Managed Fields:
    API Version:  ndslabs.org/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .:
          f:kubectl.kubernetes.io/last-applied-configuration:
      f:spec:
        .:
        f:hello:
        f:world:
    Manager:         kubectl-client-side-apply
    Operation:       Update
    Time:            2021-10-21T18:41:31Z
  Resource Version:  9012421
  Self Link:         /apis/ndslabs.org/v1/namespaces/default/workbenchuserapps/my-user-app-number-1
  UID:               ae716796-258f-4d31-8c87-9af3fc65611d
Spec:
  Hello:  it
  World:  works
Events:   <none>

Output the resource in YAML format:

$ kubectl get app my-user-app-number-1 -o yaml
apiVersion: ndslabs.org/v1
kind: WorkbenchUserApp
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"ndslabs.org/v1","kind":"WorkbenchUserApp","metadata":{"annotations":{},"name":"my-user-app-number-1","namespace":"default"},"spec":{"hello":"it","world":"works"}}
  creationTimestamp: "2021-10-21T18:41:31Z"
  generation: 1
  name: my-user-app-number-1
  namespace: default
  resourceVersion: "9012421"
  selfLink: /apis/ndslabs.org/v1/namespaces/default/workbenchuserapps/my-user-app-number-1
  uid: ae716796-258f-4d31-8c87-9af3fc65611d
spec:
  hello: it
  world: works