The operator is built with kopf. 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.
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)
-
You create a customization to create a secret.
-
there is a customization to create a
patchfor it. There are a few utility functions for that in thenuvolaris.kustomizepackage. Some of them are actually templatized (have Template name) so the actual file is generated expanding a template. All templates are undernuvolaris/templates. A templatized configuration usesJinja2. When you use templates you also have to provide thedatadictionary for the templates. -
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 astemplates=templatesand do not forget to providedata=datato provide data. -
Finally, you apply the configuration with
kube.apply- there are more utility functions runningkubectlin a pythonic way.
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 taskdeployto deploy a test CRD; - deploy in local kind with
task build-and-loadwithout having to publish it, then execute tests (see theTaskfileTest.ymlfile); - finally, test the image build and publish it with
task image-tag ; git push --tags; wait it builds and test against real kubernetes, using theTaskfile