Project: KUDO (App Definition and Development / Application Definition & Image Build)
File: 0023-enable-disable-features.md

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 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. 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. 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`. complex logic like loops to trigger multiple features enable/disable nested features evaluate multiple conditions to enable one feature 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: MIRRORMAKERENABLED 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: MIRRORMAKERENABLED 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

is `"false"` it acts like a `Delete` task, deleting the resources. 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 `MIRRORMAKERMEM` 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 `MIRRORMAKERENABLED` There are three alternatives to this approach 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. 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. 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: (MIRRORMAKERENABLED == "true") name: delete-mirror-maker tasks: delete-mirror-maker-configuration delete-mirror-maker when: (MIRRORMAKERENABLED == "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 2020-01-30 - Initial draft. (@zmalik) 2020-02-06 - Changed to implementable. (@zmalik) 2020-02-27 - Implemented in . (@zmalik)