Skip to content

Commit

Permalink
Merge branch 'release/v0.40.0' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
jelemux authored and cesmarvin committed Jan 3, 2024
2 parents 1f7a962 + 5deb662 commit dd2954b
Show file tree
Hide file tree
Showing 40 changed files with 5,389 additions and 383 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [v0.40.0] - 2024-01-03
### Added
- [#143] Track health on dogu CR

## [v0.39.2] - 2023-12-19
### Fixed
- [#145] Dogu startupProbe timeouts in airgapped environments
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ RUN make compile-generic
FROM gcr.io/distroless/static:nonroot
LABEL maintainer="hello@cloudogu.com" \
NAME="k8s-dogu-operator" \
VERSION="0.39.2"
VERSION="0.40.0"

WORKDIR /
COPY --from=builder /workspace/target/k8s-dogu-operator .
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Set these to the desired values
ARTIFACT_ID=k8s-dogu-operator
VERSION=0.39.2
VERSION=0.40.0

IMAGE=cloudogu/${ARTIFACT_ID}:${VERSION}
GOTAG=1.21
Expand Down
10 changes: 10 additions & 0 deletions api/v1/dogu_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ type DoguResources struct {
DataVolumeSize string `json:"dataVolumeSize,omitempty"`
}

type HealthStatus string

const (
PendingHealthStatus HealthStatus = ""
AvailableHealthStatus HealthStatus = "available"
UnavailableHealthStatus HealthStatus = "unavailable"
)

// DoguStatus defines the observed state of a Dogu.
type DoguStatus struct {
// Status represents the state of the Dogu in the ecosystem
Expand All @@ -89,6 +97,8 @@ type DoguStatus struct {
RequeueTime time.Duration `json:"requeueTime"`
// RequeuePhase is the actual phase of the dogu resource used for a currently running async process.
RequeuePhase string `json:"requeuePhase"`
// Health describes the health status of the dogu
Health HealthStatus `json:"health,omitempty"`
}

// NextRequeue increases the requeue time of the dogu status and returns the new requeue time
Expand Down
3 changes: 3 additions & 0 deletions api/v1/k8s.cloudogu.com_dogus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ spec:
status:
description: DoguStatus defines the observed state of a Dogu.
properties:
health:
description: Health describes the health status of the dogu
type: string
requeuePhase:
description: RequeuePhase is the actual phase of the dogu resource used for a currently running async process.
type: string
Expand Down
101 changes: 101 additions & 0 deletions controllers/deploymentController.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package controllers

import (
"context"
"fmt"
"github.com/cloudogu/k8s-dogu-operator/internal/thirdParty"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"

appsv1 "k8s.io/api/apps/v1"
metav1api "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"

"github.com/cloudogu/k8s-dogu-operator/api/ecoSystem"
doguv1 "github.com/cloudogu/k8s-dogu-operator/api/v1"
"github.com/cloudogu/k8s-dogu-operator/controllers/health"
"github.com/cloudogu/k8s-dogu-operator/internal/cloudogu"
)

const legacyDoguLabel = "dogu"

// DeploymentReconciler watches every Deployment object in the cluster and writes the state of dogus into their respective custom resources.
type DeploymentReconciler struct {
k8sClientSet thirdParty.ClientSet
availabilityChecker cloudogu.DeploymentAvailabilityChecker
doguHealthStatusUpdater cloudogu.DoguHealthStatusUpdater
}

func NewDeploymentReconciler(k8sClientSet thirdParty.ClientSet, ecosystemClient ecoSystem.EcoSystemV1Alpha1Interface, recorder record.EventRecorder) *DeploymentReconciler {
return &DeploymentReconciler{
k8sClientSet: k8sClientSet,
availabilityChecker: &health.AvailabilityChecker{},
doguHealthStatusUpdater: health.NewDoguStatusUpdater(ecosystemClient, recorder),
}
}

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
func (dr *DeploymentReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)

deployment, err := dr.k8sClientSet.
AppsV1().Deployments(request.Namespace).
Get(ctx, request.Name, metav1api.GetOptions{})
if err != nil {
return finishOrRequeue(logger,
client.IgnoreNotFound(
fmt.Errorf("failed to get deployment %q: %w", request.NamespacedName, err),
),
)
}

if !hasDoguLabel(deployment) {
// ignore non dogu deployments
return finishOperation()
}
logger.Info(fmt.Sprintf("Found dogu deployment %q", deployment.Name))

err = dr.updateDoguHealth(ctx, deployment)
if err != nil {
return finishOrRequeue(logger, fmt.Errorf("failed to update dogu health for deployment %q: %w", request.NamespacedName, err))
}

return finishOperation()
}

func finishOrRequeue(logger logr.Logger, err error) (ctrl.Result, error) {
if err != nil {
logger.Error(err, "reconcile failed")
}

return ctrl.Result{}, err
}

func hasDoguLabel(deployment client.Object) bool {
for label := range deployment.GetLabels() {
if label == legacyDoguLabel || label == doguv1.DoguLabelName {
return true
}
}

return false
}

func (dr *DeploymentReconciler) updateDoguHealth(ctx context.Context, doguDeployment *appsv1.Deployment) error {
doguAvailable := dr.availabilityChecker.IsAvailable(doguDeployment)
log.FromContext(ctx).Info(fmt.Sprintf("dogu deployment %q is %s", doguDeployment.Name, (map[bool]string{true: "available", false: "unavailable"})[doguAvailable]))
return dr.doguHealthStatusUpdater.UpdateStatus(ctx,
types.NamespacedName{Name: doguDeployment.Name, Namespace: doguDeployment.Namespace},
doguAvailable)
}

// SetupWithManager sets up the controller with the Manager.
func (dr *DeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&appsv1.Deployment{}).
Complete(dr)
}
Loading

0 comments on commit dd2954b

Please sign in to comment.