---
kep-number: 23
title: Enabling and Disabling features in KUDO Operators
short-desc: Enabling and Disabling features in KUDO Operators a.k.a. the Toggle task
authors:
  - "@zmalik"
owners:
  - "@zmalik"
creation-date: 2020-01-28
last-updated: 2020-01-28
status: implemented
---

# Enabling and Disabling features in KUDO Operators

## Summary 

KUDO enables Operator developers to create Operators and expose features of the underlying applications. 
The goal of this KEP is to facilitate operator developers to enable and disable the features in a deterministic way.

## Motivation

A feature in this KEP is defined as a set of Kubernetes objects.
We want to provide operator users a way to enable and disable features in their operator. And right now there is no operator-user friendly or operator-developer friendly way to do it. 

### Goals

Given a feature, `A` is composed of Kubernetes object `x`, `y` and `z`
 
- create or update kubernetes objects  `x`, `y` and `z`, when feature `A` is enabled.
- delete kubernetes objects  `x`, `y` and `z`, when feature `A` is disabled.

The goal of this KEP is to provide a way to create and delete objects `x`, `y` and `z`. 

### Non-Goals

- complex logic like loops to trigger multiple features
- enable/disable nested features
- evaluate multiple conditions to enable one feature

## Proposal

### Using Instance Parameters

In KUDO, specific plans can be triggered when updating a parameter. Plans are specifically formed by phases, steps and utimately by tasks.
And when talking about enabling/disabling features, we are eventually talking about the `Kind` of the Task. Currently, we have `Apply`, `Delete`, `Pipe` and `Dummy` tasks kind.
Enabling a feature is running a task of `Apply` kind and disabling is running a task of `Delete`

We propose introducing a new Task kind named `Toggle`. The Toggle kind handles Apply or Delete resources based on the value of a parameter in the Operator Instance.

A `Toggle` task will look like:

```
tasks:
  - name: mirror-maker-configuration
    kind: Toggle
    spec:
      parameter: MIRROR_MAKER_ENABLED
      resources:
        - mirror-maker-cm.yaml
        - mirror-maker.yaml
```


the parameter used in task would be defined in the parameters for the Operator, and must evaluate to a boolean value.
```
apiVersion: kudo.dev/v1beta1
parameters:
  - name: MIRROR_MAKER_ENABLED
    default: "false"
    trigger: mirror-maker-plan
```

And the plan triggered by the parameter will be the one using `Toggle` tasks in their steps.

```
plans:
  mirror-maker-plan:
    strategy: serial
    phases:
      - name: deploy-mirror-maker
        strategy: serial
        steps:
          - name: configuration
            tasks:
              - mirror-maker-configuration
          - name: deploy
            tasks:
              - mirror-maker
```

If the `spec.parameter` is `"true"`, `Toggle` task acts like `Apply` task, applies the provided resources and waits for them to become healthy.
If the `spec.parameter` is `"false"` it acts like a `Delete` task, deleting the resources.

### Limitations

However the `Toggle` task will have limitations like:

- KUDO Operator must define the parameter which will be evaluated as a boolean.
- The defined parameter must evaluate to a boolean value
- Multiple parameters can trigger the same plan, but only one parameter will be evaluated

For the last use case, e.g., we can have a parameter `MIRROR_MAKER_MEM` which triggers the `mirror-maker-plan` but
the parameter which will decide in `Toggle Task` if the kubernetes objects are created/updated or deleted will be `MIRROR_MAKER_ENABLED`

## Alternatives

There are three alternatives to this approach

### Independent enabledFeatures list in KUDO Instance
Add a specific feature field like `Instance.spec.enabledFeatures` and drop using `Instance.spec.parameters` for enabling features in operators. 
That would mean redesigning the instance updates architecture. As right now, this is the only way to updates the KUDO Instances. 
But the impact of introducing the new field would be quite limiting as it won't provide much more than what we already have with parameters 

### Reconcile the world
Reconcile the world. KUDO creates a state of an instance based on `Instance` and `OperatorVersion` objects. And on
any update it adds/updates/removes any differences it founds between Kubernetes objects and state generated by KUDO.

This approach might suggest as a solution for enabling and disabling features, but its scope can be way more significant and not just limited to this KEP.
And should be reviewed as an individual feature with all impact it would bring. From how to debug and recover from a bad state as it won't be reduced to pure `Apply/Delete` scope.

### Charge operator plans with conditional expressions
The current suggestion encapsulates the if-else logic in a new task type. 

However, both branches (true and false) are already covered by the Apply and Delete tasks so we might as well put the if-else logic directly into the plan like:

```
plans:
mirror-maker-plan:
  strategy: serial
  phases:
    - name: mirror-maker-phase
      strategy: serial
      steps:
        - name: apply-mirror-maker
          tasks:
            - apply-mirror-maker-configuration
            - apply-mirror-maker
          when: (MIRROR_MAKER_ENABLED == "true")
        - name: delete-mirror-maker
          tasks:
            - delete-mirror-maker-configuration
            - delete-mirror-maker
          when: (MIRROR_MAKER_ENABLED == "false")
```
Here, e.g. apply-mirror-maker is a simple Apply and delete-mirror-maker a Delete kind of task (omited here for brevity).

**Pros**:

- we don't need a new task type
- more conditions flexibility: it's easy to extend the when to whatever we need it to be

**Cons**:

- YAMLy programming language
- hard to debug


## Implementation History

- 2020-01-30 - Initial draft. (@zmalik)
- 2020-02-06 - Changed to implementable. (@zmalik)
- 2020-02-27 - Implemented in [#1361](https://github.com/kudobuilder/kudo/pull/1361). (@zmalik)
