blob: b3b6bb6e85a994fd11bc3d7e8bf93ab6fb4769ed [file] [log] [blame] [view]
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
~
-->
# Design Document
The operator is built with [`kopf`](https://kopf.readthedocs.io/en/stable/). It is basically a server that will react to
events coming from Kubernetes. The main event to react to is the deployment of a Custom Resource Definition that
configures OpenWhisk and all the related components.
All the code is in the package `nuvolaris`. Events are handled in `main.py`.
Each event handlers uses utility functions you can find the various service specific files like `openwhisk` or `couchdb`.
## Development Workflow
In general the operator react to events and execute _kustomizations_.
To develop,
- you start and test writing a base YAML configuration in code;
- you can then modify this base configuration in code using `kustomize` (wrapped in python);
- finally you apply the configuration with `kubectl` (wrapped in python).
A good example of how to build a configuration is the following.
Start creating a basic definition under `deploy` for example `couchdb`. All the utils searches set of deployments under
some folder under `deploy`.
Then you can do this (obvious details omitted)
```
1 kust = kus.secretLiteral("couchdb-auth", user, pasw)
2 kust += kus.patchTemplate("couchdb", "set-attach.yaml", data)
3 spec = kus.kustom_list("couchdb", kust, templates=["couchdb-init.yaml"], data=data)
4 kube.apply(spec)
```
1. You create a customization to create a secret.
2. there is a customization to create a `patch` for it. There are a few utility functions for that in the
`nuvolaris.kustomize` package. Some of them are actually _templatized_ (have Template name) so the actual file is
generated expanding a template. All templates are under `nuvolaris/templates`. A _templatized_ configuration uses
`Jinja2`. When you use templates you also have to provide the `data` dictionary for the templates.
3. Once finished you generate a configuration to be applied. Usually it is better to be a series of configuration,
hence you invoke `kustom_list`. Note that kustom list, in addition to customize a configuration, can also add more
configuration in the form of templates. Specify the templates to use as `templates=templates` and do not forget to
provide `data=data` to provide data.
4. Finally, you apply the configuration with `kube.apply` - there are more utility functions running `kubectl` in a
pythonic way.
# Testing
There are multiple level of testings:
- first test algorithm with unit tests (`task utest` - I use a lot doctest);
- then test with integration tests without starting the operator (`task itest`) - tests uses ipython and assertions;
- run the operator locally without deploying it (with `task run`) and run task `deploy` to deploy a test CRD;
- deploy in local kind with `task build-and-load` without having to publish it, then execute tests
(see the `TaskfileTest.yml` file);
- finally, test the image build and publish it with `task image-tag ; git push --tags`; wait it builds and test
against real kubernetes, using the `Taskfile`