/example-cndi-templates

demonstration of how to write cndi templates

example-cndi-templates

There are a few example templates here to help you get started in building your own! The smallest one can be found here.

cndi init --interactive --template https://raw.githubusercontent.com/polyseam/example-cndi-templates/main/aws/tiny.jsonc

secret-app-commands


Wbat is a CNDI Template?

A cndi Template is a JSON file that CNDI can parse in order to provide a simplified deployment experience for some cloud-native application. The template declares 3 "output" blocks, each relating to a particular file, and one "prompts" array which allows each output to be customized by end users. Let's start by looking at the "prompts" array.

prompts

The prompts array is a list of questions that CNDI will ask the user when they run cndi init --interactive, if the user is not in interactive mode the value will fallback to the default provided.

{
  "prompts": [
    {
      // each prompts object is created leveraging the `prompts` module from
      // https://cliffy.io/docs/prompt#prompt-list
      // the following input types are all supported:
      // "Input" | "Secret" | "Confirm" | "Toggle" | "Select" | "List" | "Checkbox" | "Number"
      "type": "Input",
      "name": "argocdDomainName",
      "message": "What domain name should argocd be deployed on?",
      "default": "argocd.example.com"
    },
    {
      "type": "Secret",
      "name": "myAirflowPassword",
      "message": "Please enter a default password for Airflow:",
      "default": "admin"
    }
  ]
}

When using the --interactive flag in CNDI each of these prompts will provide an interactive prompt to populate the value.

If the user does not provide a value or if the user is not using interactive mode, the default will be used.

These values are then accessible inside of a template "output" using the following syntax: {{ $.cndi.prompts.responses.<prompt_name> }}.

For example, if we wanted to use the value of argocdDomainName in a template we would use the following syntax: {{ $.cndi.prompts.responses.argocdDomainName }}.

outputs

cndi-config

Summary

The outputs["cndi-config"] block is used to provide a templating interface around the cndi-config.jsonc file that acts as the core of each CNDI project. The shape of the object is as follows:

{
  "outputs": {
    "cndi-config": {
      "infrastructure": {
        /*...*/
      },
      "cluster_manifests": {
        /*...*/
      },
      "applications": {
        /*...*/
      }
    }
  }
}

Let's look at an example of leveraging a "prompt" entry to populate a value into the cndi-config.jsonc file.

Example

Input:

{
  "cndi-config": {
    "applications": {
      /*...*/
    },
    "infrastructure": {
      /*...*/
    },
    "cluster_manifests": {
      "argo-ingress": {
        "apiVersion": "networking.k8s.io/v1",
        "kind": "Ingress",
        "metadata": {
          /*...*/
        },
        "spec": {
          "tls": [
            {
              "hosts": ["{{ $.cndi.prompts.responses.argocdDomainName }}"],
              "secretName": "lets-encrypt-private-key"
            }
          ],
          "rules": [
            {
              "host": "{{ $.cndi.prompts.responses.argocdDomainName }}",
              "http": {
                "paths": [
                  /*...*/
                ]
              }
            }
          ]
        }
      }
    }
  }
}

Output:

{
  "applications": {
    /*...*/
  },
  "infrastructure": {
    /*...*/
  },
  "cluster_manifests": {
    "argo-ingress": {
      "apiVersion": "networking.k8s.io/v1",
      "kind": "Ingress",
      "metadata": {
        /*...*/
      },
      "spec": {
        "tls": [
          {
            "hosts": ["myargocd.creedthoughts.comgov.uks"],
            "secretName": "lets-encrypt-private-key"
          }
        ],
        "rules": [
          {
            "host": "myargocd.creedthoughts.comgov.uks",
            "http": {
              "paths": [
                /*...*/
              ]
            }
          }
        ]
      }
    }
  }
}

env

Summary

The env block is used to provide a templating interface around the .env file which is used for values which should not be written directly to version control. The shape of the object is as follows:

{
  "outputs":{
    {...},
    "env": {
      "extend_basic_env": "aws",
      "entries": [
        {
          "name": "POSTGRES_PORT",
          "value": "5432"
        }
      ]
    }
  }
}

The extend_basic_env key is used to extend the built-in .env file cndi provides for a given deployment target. CNDI provides the necessary prompts for each deployment target so that the .env file can be extended after those basic values are collected. The value of extend_basic_env should be the name of the deployment target you wish to extend, for example gcp, azure or aws as shown above.

It's also possible to leverage "prompt" values here in outputs["env"], let's look at an example:

Example

Input:

{
  "prompts": [
    {
      "name": "secretAppPassword",
      "type": "Input",
      "message": "What password should be used for SecretApp?"
    }
  ],
  "outputs": {
    "env": {
      "extend_basic_env": "aws",
      "entries": [
        {
          "name": "SECRETAPP_PASSWORD",
          "value": "{{ $.cndi.prompts.responses.secretAppPassword }}"
        }
      ]
    }
  }
}

Output:

SECRETAPP_PASSWORD='top_secret123'

readme

Summary

The final block of a cndi template is the readme block, which behave similarly to the other two sections. We specify a readme block in order to provide a templating interface around the README.md file that is generated when a user runs cndi init. The shape of the object is as follows:

{
  "outputs": {
    "cndi-config":{...},
    "env":{...},
    "readme": {
      "extends_basic_readme": "aws",
      "template_section": "## This is a sample readme section dedicated to this template"
    }
  }
}

The extends_basic_readme key is used to extend the README.md file for a given deployment target. CNDI provides the necessary readme section for each deployment target so that the README.md file can be extended with more content after those basic readme sections have been written to the file.

The value of extends_basic_readme should be the name of the deployment target you wish to extend, for example gcp, azure or aws as shown above.

Example

Input:

{
  "prompts":[{...}],
  "outputs":{
    "cndi-config":{...},
    "env":{...},
    "readme": {
      "extend_basic_readme": "aws",
      "template_section": "# logging into secret app\n\nvisit secretapp.cndi.dev and type in the passphrase \"{{ $.cndi.prompts.responses.secretAppPassword }}\""
    }
  }
}

Output:

<!-- Lots more content above -->

## aws

This cluster will be deployed on [Amazon Web Services](https://aws.com). When
your cluster is initialized the next step is to go to your domain registrar and
create an CNAME record for your Airflow instance, and another for ArgoCD. Both
entries should point to the single load balancer that was created for your
cluster.

## This is a simple readme section that is template specific

neato!

all together now!

{
  "prompts": [
    {...}
  ],
  "outputs":{
    "cndi-config": {
      "infrastructure":{...},
      "cluster_manifests":{...},
      "applications":{...}
    },
    "env": {
      "extend_basic_env": "aws",
      "entries": [{...}]
    },
    "readme": {
      "extends_basic_readme": "aws",
      "template_section": "##This is a sample readme\n\nneato!"
    }
  }
}

Included Examples

This repository contains example templates for use within cndi. There is at least one unit test within the CNDI project that verifies remote templates are working correctly by installing a template from this repository.