operator-utils library

This library layers on top of the Operator SDK, having set of utilities function as a library to easily create Kubernetes operators.
Kubernetes / OpenShift Version Support
The operator-utils project aims to support the 2 most recent OpenShift minor versions:
- main branch currently supports K8S 1.13 / OCP 4.2
- For K8S 1.14 support, please refer to k8s-1.14 branch
- For K8S 1.16 / OpenShift 4.3 support, please refer to k8s1.16_ocp4.3 branch
- For K8S 1.17 / OpenShift 4.4 support, please refer to k8s1.17_ocp4.4 branch
Declaring operator-utils dependency
Regardless of dependency framework, we suggest following the best practice of declaring any and all dependencies your project utilizes regardless of target branch, tag, or revision.
With regards to operator-utils, please carefully consider the given version support information above when declaring your dependency, as depending on or defaulting to master branch will likely result in future build complications as our project continues to evolve and cycle minor version support.
- Dep example specifying REVISION:
[[constraint]]
name = "github.com/RHsyseng/operator-utils"
revision = "232650febd728455482b3c780c79a9ac0be62b50"
- Go.mod example specifying REVISION:
github.com/RHsyseng/operator-utils v0.0.0-20200108204558-82090ef57586
Features
- managing CR and CRD validation
- pods deployment status
- resource comparison, adding, updating and deleting
- platform detection Kubernetes VS Openshift
Managing CR and CRD validation
Operator util library use package validation
for validate the CRD and CR file, these function use as a unit test within operator
CRD validation Usage:
schema := getCompleteSchema(t)
missingEntries := schema.GetMissingEntries(&sampleApp{})
for _, missing := range missingEntries {
if strings.HasPrefix(missing.Path, "/status") {
//Not using subresources, so status is not expected to appear in CRD
} else {
assert.Fail(t, "Discrepancy between CRD and Struct", "Missing or incorrect schema validation at %v, expected type %v", missing.Path, missing.Type)
}
}
CR validation Usage:
schema, err := New([]byte(schemaYaml))
assert.NoError(t, err)
type myAppSpec struct {
Number float64 `json:"number,omitempty"`
}
type myApp struct {
Spec myAppSpec `json:"spec,omitempty"`
}
cr := myApp{
Spec: myAppSpec{
Number: float64(23),
},
}
missingEntries := schema.GetMissingEntries(&cr)
assert.Len(t, missingEntries, 0, "Expect no missing entries in CRD for this struct: %v", missingEntries)
A full example is provided here
Pods deployment status
showes the status of the deployment on OLM UI in the form of PI chart, as seen in below screenshot

Usage:
Below seen line required to add into types.go status structure
PodStatus olm.DeploymentStatus `json:"podStatus"`
Add these lines into CSV file inside statusDescriptors section:
statusDescriptors:
- description: The current pods
displayName: Pods Status
path: podStatus
x-descriptors:
- "urn:alm:descriptor:com.tectonic.ui:podStatuses"
For DeploymentConfig deployment status:
var dcs []oappsv1.DeploymentConfig
deploymentStatus := olm.GetDeploymentConfigStatus(dcs)
if !reflect.DeepEqual(instance.Status.Deployments, deploymentStatus) {
r.reqLogger.Info("Deployment status will be updated")
instance.Status.Deployments = deploymentStatus
err = r.client.Status().Update(context.TODO(), instance)
if err != nil {
r.reqLogger.Error(err, "Failed to update deployment status")
return err
}
}
For StatefulSet Deployment status:
var status olm.DeploymentStatus
sfsFound := &appsv1.StatefulSet{}
err := client.Get(context.TODO(), namespacedName, sfsFound)
if err == nil {
status = olm.GetSingleStatefulSetStatus(*sfsFound)
} else {
dsFound := &appsv1.DaemonSet{}
err = client.Get(context.TODO(), namespacedName, dsFound)
if err == nil {
status = olm.GetSingleDaemonSetStatus(*dsFound)
}
}
Resource comparison (adding, updating and deleting)
Common function for listing, adding, updating, deleting kubernetes objects like seen below:
List of objects that are deployed
reader := read.New(client).WithNamespace(instance.Namespace).WithOwnerObject(instance)
resourceMap, err := reader.ListAll(
&corev1.PersistentVolumeClaimList{},
&corev1.ServiceList{},
&appsv1.StatefulSetList{},
&routev1.RouteList{},
)
Compare what's deployed with what should be deployed
requested := compare.NewMapBuilder().Add(requestedResources...).ResourceMap()
comparator := compare.NewMapComparator()
deltas := comparator.Compare(deployed, requested)
Adding the objects:
added, err := writer.AddResources(delta.Added)
Updating the objects:
updated, err := writer.UpdateResources(deployed[resourceType], delta.Updated)
Removing the objects:
removed, err := writer.RemoveResources(delta.Removed)
A full usage is provided here
To detect platform whether operator is running on kuberenete or openshift or what version of openshift is using
info, err := pv.GetPlatformInfo(c.discoverer, c.config)
A full example is provided here
Who is using this Library
operator-utils is used by several Red Hat product & community operators, including the following:
Contributing
All bugs, tasks, fixes or enhancements should be tracked as GitHub Issues & Pull Requests.