operator-tools

module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 24, 2020 License: Apache-2.0

README

operator-tools

This is a collection of tools to speed up the implementation of Kubernetes Operators on top of controller-runtime.

GenericResourceReconciler

GenericResourceReconciler reconciles a single Kubernetes object against the API Server.

It creates the object if it doesn't exist or removes it in case its desired state is absent.

It uses the ObjectMatcher library to be able to tell if an already existing object needs to be updated or not.

It depends on logr logger and the controller-runtime client that is available in a typical kubebuilder or operator-sdk project.

Example:

package main

import (
	corev1 "k8s.io/api/core/v1"
	github.com/go-logr/logr
	"github.com/banzaicloud/operator-tools/pkg/reconciler"
	runtimeClient "sigs.k8s.io/controller-runtime/pkg/client"
)

func example(client runtimeClient.Client, logger logr.Logger) {
	
  resourceReconciler := reconciler.NewReconciler(client, logger, reconciler.ReconcilerOpts{})
  
  serviceObject := &corev1.Service{
    Spec: corev1.ServiceSpec{
      Ports: []corev1.ServicePort{
        {
          Protocol:		corev1.ProtocolTCP,
          Name:				"example",
          Port:				80,
          TargetPort: 8080,
        },
      },
      Selector:	map[string]string{
        "app": "example",
      },
      Type:			corev1.ServiceTypeClusterIP,
      ClusterIP: "None",
    },
  }
  
  result, err := resourceReconciler.ReconcileResource(serviceObject, reconciler.StatePresent)
}

This feature is currently only covered with tests in the logging operator, but this is a subject to change soon.

Secret & SecretLoader

Secret is a type to be used in CRDs to abstract the concept of loading a secret item instead of defining it with it's value directly.

Currently it support Kubernetes secrets only, but it can be extended to refer to secrets in custom secret stores as well.

There are two main approaches to load secrets and one for testing.

  1. Load the secrets and return with their value directly if ValueFrom is set.
  2. Load the secrets in the background if MountFrom is set, but return only the full path where they should be available in a container. It's the callers responsibility to make those secrets available on that given path, e.g. by creating an aggregated secret with all the referenced secrets and mount it into the container through a secret volume (this is how we use it).
  3. Load the value directly if Value is set. (This is only good for testing.)

Once you're done with configuration you can create the SecretLoader and load your secrets through it.

mountSecrets := &secret.MountSecrets{}
secretLoader := secret.NewSecretLoader(client, namespace, "/path/to/mount", mountSecrets)

Then you can load the secrets. The following steps can be made more dynamic, like it is beeing used in the logging operator: https://github.com/banzaicloud/logging-operator/blob/master/pkg/sdk/model/types/stringmaps.go

// get the secretValue and use it as you like in an application configuration template for example
secretValue, err := secretLoader.Load(yourCustomResourceType.Spec.ExampleSecretField)

// get the path to the mount secret and use it as you like in an application configuration template for example
secretPath, err := secretLoader.Load(yourCustomResourceType.Spec.ExampleMountSecretField)

// render the configuration template and create a new secret from it that will be mounted into the container
appConfigSecret := &corev1.Secret{}
renderedTemplate := renderTemplate(secretValue, secretPath)
appConfigSecret.Data["app.conf"] = renderedTemplate

// create the combined secret to be mounted to the container on "/path/to/mount"
combinedSecret := &corev1.Secret{}
for _, secret := range *mountSecrets {
  combinedSecret.Data[secret.MappedKey] = secret.Value
}

For a full example please check out the logging operator code.

Also, this feature is currently only covered with tests in the logging operator, but this is a subject to change soon.

KubernetesVolume

Configure volumes in custom types for underlying pods in a uniform way.

type SomeCustomApp struct {
	BufferStorage *volume.KubernetesVolume `json:"bufferStorage,omitempty"` 
}

And this is how you would configure it through yaml

someCustomApp:
  bufferStorage:
    hostPath:
      path: "/buffer" # set this here, or provide a default in the code

In the operator you can use the GetVolume method on the object in a generic way:

// provide a default path if hostPath is used but no actual path has been configured explicitly
someCustomApp.bufferStorage.WithDefaultHostPath("/opt/buffer")

volume := someCustomApp.bufferStorage.GetVolume(
  "volumeName",
))

Directories

Path Synopsis
module
helm Module
pkg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL