Imperative Framework

Topic Objectives

In this topic we will discuss:

  • Imperative vs. Declarative

  • Why we need the imperative framework

Imperative vs. Declarative Actions

What’s the difference between Imperative and Declarative actions?

Declarative is when we describe what we want in our clusters, and we let the GitOps controller reconcile the difference between what’s in Git and what’s in the cluster.

Imperative is where we take action on the cluster. A simplified way of thinking about this is all of the actions done by hand (e.g. oc apply -f, kubectl)

During the development of the imperative framework there as a realization that there was a generalized need to support a limited mechanism for running these imperative actions in the most declarative way possible.

We needed an automated, self-contained and supportable mechanism to interact with elements of OpenShift that could not be predicted prior to installation.

Some examples of when this is necessary:

  • The management of secrets across clusters - the need to make clusters mutually trust each others’ Certificate Authorities and transfer of tokens/credentials

Defining an imperative action

The following code snippet is from the values-hub.yaml in the multicloud-gitops pattern
  imperative:
    # The default schedule is every 10 minutes: imperative.schedule
    # Total timeout of all jobs is 1h: imperative.activeDeadlineSeconds
    # imagePullPolicy is set to always: imperative.imagePullPolicy
    jobs:
      - name: hello-world
        # ansible playbook to be run
        playbook: common/ansible/playbooks/hello-world/hello-world.yaml
        # per playbook timeout in seconds
        timeout: 234
        # verbosity: "-v"

When the pattern is deployed a cronJob is created in the imperative namespace. By default it is set to run every 10 minutes.

The cronJob (see below) has been parameterized so we can change the intervals and define our imperative playbooks.

apiVersion: batch/v1
kind: CronJob
metadata:
  name: {{ $.Values.clusterGroup.imperative.cronJobName }}
  namespace: {{ $.Values.clusterGroup.imperative.namespace}}
spec:
  schedule: {{ $.Values.clusterGroup.imperative.schedule | quote }}
  # if previous Job is still running, skip execution of a new Job
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      activeDeadlineSeconds: {{ $.Values.clusterGroup.imperative.activeDeadlineSeconds }}
      template:
        metadata:
          name: {{ $.Values.clusterGroup.imperative.jobName }}