Interaction with Kubernetes API from Salt

Context

In MetalK8s we need to interact with Kubernetes API from Salt in order to create and edit various objects. Since the Salt Kubernetes module is not flexible enough (at least today) we decided to build our own Salt module that will cover all we need in MetalK8s. This Salt module relies on python-kubernetes lib so that we have a proper python class for every Kubernetes object and we can validate the object content without any call to the actual Kubernetes API.

But python-kubernetes lib is a bit late on Kubernetes versions (at the time of writing, the latest python-kubernetes is for k8s-1.18 and k8s 1.22.1 just came out) so it means that some Kubernetes objects from the latest versions cannot be managed by this python lib.

Here, we want to solve this issue and make sure when a new Kubernetes version comes out that we can easily support interaction with all the Kubernetes API from Salt.

Design Choices

Instead of relying on model and API object from python-kubernetes, which is the representation from openapi of a specific Kubernetes version, we can directly use python-base which is what is used in the back by python-kubernetes.

This python-base has a DynamicClient that can be used to manage any Kubernetes objects no matter the Kubernetes version. It’s really more flexible it’s mean that we do not validate the manifest we send to Kubernetes API, but the manifest can be validated using kubernetes-validate lib.

This kubernetes-validate lib can have the same issue as python-kubernetes as it needs to be generated for every Kubernetes version, but it seems a bit more up-to-date and this validation is not strictly needed to create the objects, so if a specific version of kubernetes-validate is not yet released we could just remove the validation waiting for a new version to be released.

In order to validate the request or test it we can use dryRun parameter from Kubernetes API, it could be really usefull especially when using test mode from Salt.

Rejected Design Choices

Migrate to kubectl

To have proper support of the full Kubernetes API we could use directly kubectl, which is the CLI build as part of Kubernetes.

The advantage of using kubectl is that we do not have anything to do in order to support interaction with the new Kubernetes API and nothing (or almost) to maintain in our Salt module that uses this CLI.

This approach was rejected because we need to use a CLI in order to do some “HTTP query” to Kubernetes API that’s a bit odd and it add an extra layer that does not bring a lot of value compare to selected design.

Contribute to python-kubernetes Lib

We could contribute to python-kubernetes in order to make it compatible with the latest versions of Kubernetes.

This approach was rejected, for the moment, because python-kubernetes start to be really late on Kubernetes versions, and this work, likely, needs to be done for every new Kubernetes version.

Direct HTTP Query to Kubernetes API from Python

We could build a Salt module that directly interacts with Kubernetes API the way we want so that we do not rely on python-kubernetes but only implement the interactions we need.

This approach was rejected because it means this Salt module needs to be maintained for every new Kubernetes version and for every API/object we want to support.

Implementation Details

First Iteration

In order to be able to use DynamicClient from python-base we still need to install a python-kubernetes version since python-base is not packaged, but we do not need this python-kubernetes version to be “compatible” with the Kubernetes version we run since we rely on DynamicClient that should be compatible with all Kubernetes versions.

Rework all Salt execution modules that interact with Kubernetes so that it simply uses DynamicClient, some examples can be found here.

The Salt state module will likely not be changed and will have the same function as today (object_present, object_absent, object_updated) so it means most of the Salt SLS will not be changed as well.

The Salt execution module will change a bit but the function exposed will likely stay the same.

Most of the logic from the Kubernetes salt utils module can be removed.

Second Iteration (if needed)

If needed we can add some validation.

We can validate the manifest content before sending it to Kubernetes API, to do so, we need to install kubernetes-validate python lib in the Salt master container, and then it can be used easily directly from a DynamicClient instance using validate function.

Use dryRun parameter from Kubernetes API so that we can validate the request.

Documentation

Normally nothing to change.

Test Plan

Update the Salt unit tests for the execution module.

Existing end to end tests should be sufficient.