# Templates beta

Templates allows users to quickly start writing a stack by selecting a pre-defined template. Templates serve as a starting point for creating stacks and can be used to introduce features, define patterns, and establish best practices for teams to follow. This documentation provides an overview of the Stack Template feature, explains how to use existing templates, and provides guidance on writing custom templates.

# Using a template

When creating a stack within the Cycloid UI, you can start from a template by following these steps:

  • Navigate to the Stacks section in the Cycloid UI.
  • Click on the Create Stack button.
  • Select the Create from template option.
  • In the stack creation form, select the desired template from the available options.
  • Customize the stack parameters and settings as needed.
  • Click Create Stack to create the stack using the selected template.

Voilà, your stack is created! Most often, the generated stack contains a README.md file that explains how to use it, and eventually what needs to be edited.

Using a template provides a foundation for your stack, including pre-configured resources, configurations, and other relevant settings. It enables you to start working on your stack more efficiently, saving time and effort.

# Writing your own templates

Cycloid allows you to create custom stack templates tailored to your specific use cases.

# Template structure

A template is nearly identical to a stack, with similar structure and files. It needs a .cycloid.yml file, and may contain a pipeline, Terraform modules, Ansible playbooks, a README.md file and any other relevant files.

The only differences are:

  1. Template .cycloid.yml files must have the template attribute set to true.
  2. Templates can take advantage of pongo2 templating.

For example, given the following directory structure:

.
├── .cycloid.yml
├── .forms.yml
├── README.md
├── pipeline
│   ├── pipeline.yml
│   └── variables.sample.yml
└── terraform
    └── provider.tf
1
2
3
4
5
6
7
8
9

With the following .cycloid.yml file:







 











version: 2

name: Template                         # The name of the template
canonical: template-canonical          # The unique canonical of the template
author: '{{ stack_author }}'           # The author of the template
description: 'A template description.' # The template description
template: true                         # The attribute that differentiate a template from a stack.

config:
  default:
    name: 'Default'
    pipeline:
      pipeline:
        path: 'pipeline/pipeline.yml'
      variables:
        path: 'pipeline/variables.sample.yml'
        destination: '($ project $)/pipeline/variables-($ environment $).yml'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Templates, just like stacks, need to be imported in catalog repositories. You may have catalog repositories dedicated for templates, or even have templates and stacks together in a single repo.

# pongo2 templating

Templates rely on the pongo2 templating engine (opens new window), a Django-syntax like templating-language for Go. pongo2 allows you to embed dynamic content and logic within your templates through the use of variables, filters and tags. The template files are compiled when the stack is created.

{# This is a short example to give you a quick overview of pongo2's syntax. #}
echo "author: {{ stack_author }}"

{% if stack_usecase == "aws" %}
echo "Provider: Amazon Web Services"
{% elif stack_usecase == "gcp" %}
echo "Provider: Google Cloud Platform"
{% endif %}
1
2
3
4
5
6
7
8

See the Django documentation (opens new window) for more info on the syntax.

Note

pongo2 templating is only available in stack templates, and not in stacks themselves.

# Variables

Several variables are exposed and can be used within your stack templates:

Variable name Description
api_url The URL of the Cycloid API
stack_author The username of the user who creates the stack
stack_canonical The stack canonical filled in by the user
stack_path The path of the generated stack in the catalog repository
stack_usecase The key of the selected use case
scs_canonical The canonical of the target catalog repository
scs_cred_path The path in Vault of the target catalog repository credential
scs_cred_type The type of the target catalog repository credential (ssh or http)

# README files

A template may contain a README.md file, which will be copied over to the stack. Upon creating a stack from a template, users will be redirected to the stack details page where the stack README is displayed. It's a good idea to rely on this README to guide users on how to use and manipulate their stack.

# Multi use-cases templates

Like stacks, templates may include multiple use-cases to cover a variety of scenarios. When selecting a multi use-cases template, users will have to select the desired use-case to use in their stack. The output stack will only contain the selected use-case, making the stack easier to understand.

Note

Templates cannot generate multi use-cases stacks. Only a single use-case will be kept when generating a stack.

When a template use-cases are very similar, with only small differences, they can be combined in a single files by using pongo2 templating to handle the differences. See this example provider.tf file:





 



















 











 

variable "organization" {}
variable "project" {}
variable "env" {}

{% if stack_usecase == "aws" %}
provider "aws" {
  access_key = var.aws_cred.access_key
  secret_key = var.aws_cred.secret_key
  region     = var.aws_region
  default_tags {
    tags = {
      "cycloid.io" = "true"
      env          = var.env
      project      = var.project
      organization = var.organization
    }
  }
}
variable "aws_cred" {}
variable "aws_region" {
  description = "AWS region to launch servers."
  default     = "eu-west-1"
}

{% elif stack_usecase == "gcp" %}
terraform {
  required_providers {
    google = {
      source  = "google"
      version = "~> 2.18.0"
    }
  }
}
provider "google" { project = var.gcp_project }
variable "gcp_project" { default = "cycloid-demo" }
variable "gcp_zone" { default = "europe-west1-b" }
{% endif %}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

But in other situations, use-cases can be widely different and require specific files. In this scenario, use-case specific files can be organized in folders named after the use-case keys (as defined in .cycloid.yml), placed in a extra-templates directory located at the root of the template.

Given the following .cycloid.yml definition, where we define two use-cases:










 







 










version: 2

name: Template                         # The name of the template
canonical: template-canonical          # The unique canonical of the template
author: '{{ stack_author }}'           # The author of the template
description: 'A template description.' # The template description
template: true                         # The attribute that differentiate a template from a stack.

config:
  foo:
    name: 'Foo'
    description: 'An example use-case'
    pipeline:
      pipeline:
        path: 'foo-pipeline.yml'
      variables:
        path: 'foo-variables.sample.yml'
        destination: '($ project $)/pipeline/variables-($ environment $).yml'
  bar:
    name: 'Bar'
    description: 'Another example use-case'
    pipeline:
      pipeline:
        path: 'bar-pipeline.yml'
      variables:
        path: 'bar-variables.sample.yml'
        destination: '($ project $)/pipeline/variables-($ environment $).yml'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

And considering we need two entirely different pipelines for the two use-cases, we can use the following template directory structure:






 
 
 
 
 
 

.
├── .cycloid.yml
├── .forms.yml
├── README.md
└── extra-templates
    ├── foo # Folder name matches the use-case key
    │   ├── foo-pipeline.yml
    │   └── foo-variables.sample.yml
    └── bar # Folder name matches the use-case key
        ├── bar-pipeline.yml
        └── bar-variables.sample.yml
1
2
3
4
5
6
7
8
9
10
11

When creating a stack with the use-case foo, files and folders placed under extra-templates/foo/ will be moved in the template root directory, and the extra-templates directory removed. Files from extra-templates/foo/ will overwrite any file with the same name already present in the template root directory.

Following our previous example, creating a stack with the foo use-case would give us the following directory structure:





 
 

.
├── .cycloid.yml
├── .forms.yml
├── README.md
├── foo-pipeline.yml
└── foo-variables.sample.yml
1
2
3
4
5
6

And here is what users will see when selecting this template:

# Enabling Cycloid templates

Cycloid maintains a set of basic templates (opens new window) that serve as a starting point for writing your first stacks. These templates showcase minimal and well-documented examples, providing a solid foundation for building your own stacks and exploring the capabilities of Cycloid.

To access Cycloid templates, create a catalog repository configured with the https://github.com/cycloidio/bootstrap-stacks.git URL on the master branch. This repository is public and doesn't require credentials.

Once the configuration is complete, you will be able to see and select Cycloid templates when creating stacks in the UI. These templates provide a foundation for building your own stacks and exploring the capabilities of Cycloid.

Note

If you are unable to see Cycloid templates, ensure that your catalog repository is properly configured and linked to the correct GitHub repository.