Skip to content

Commit

Permalink
Add barebones termination controller
Browse files Browse the repository at this point in the history
A very bare bones termination controller to watch Consoles, determine
why their pods fail and update conditions on their status.
  • Loading branch information
Theo Barber-Bany committed Feb 17, 2022
1 parent e0d9ffb commit c9d7cc6
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 0 deletions.
14 changes: 14 additions & 0 deletions cmd/workloads-manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
workloadsv1alpha1 "github.com/gocardless/theatre/v3/apis/workloads/v1alpha1"
"github.com/gocardless/theatre/v3/cmd"
consolecontroller "github.com/gocardless/theatre/v3/controllers/workloads/console"
terminationcontroller "github.com/gocardless/theatre/v3/controllers/workloads/console/termination"
"github.com/gocardless/theatre/v3/pkg/signals"
"github.com/gocardless/theatre/v3/pkg/workloads/console/events"
)
Expand Down Expand Up @@ -102,6 +103,19 @@ func main() {
app.Fatalf("failed to create controller: %v", err)
}

// controller to observe termination states
if err = (&terminationcontroller.TerminationReconciler{
// Client: mgr.GetClient(),
// LifecycleRecorder: lifecycleRecorder,
// ConsoleIdBuilder: idBuilder,
// Log: ctrl.Log.WithName("controllers").WithName("termination-watcher"),
// Scheme: mgr.GetScheme(),
// SessionPubsubProjectId: *sessionPubsubProjectId,
// SessionPubsubTopicId: *sessionPubsubTopicId,
}).SetupWithManager(ctx, mgr); err != nil {
app.Fatalf("failed to create termination watching controller: %v", err)
}

// console authenticator webhook
mgr.GetWebhookServer().Register("/mutate-consoles", &admission.Webhook{
Handler: workloadsv1alpha1.NewConsoleAuthenticatorWebhook(
Expand Down
29 changes: 29 additions & 0 deletions controllers/workloads/console/termination/handler/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package handler

import (
workloadsv1alpha1 "github.com/gocardless/theatre/v3/apis/workloads/v1alpha1"
"github.com/gocardless/theatre/v3/controllers/workloads/console/termination/status"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func main() {
}

type TerminationHandler struct {
client client.Client
}

type Options struct{}

func NewTerminationHandler(c client.Client, opts *Options) *TerminationHandler {
return &TerminationHandler{
client: c,
}
}

func (h *TerminationHandler) Handle(instance *workloadsv1alpha1.Console) (*status.Result, error) {
switch instance.Status.Phase {
default:
return nil, nil
}
}
10 changes: 10 additions & 0 deletions controllers/workloads/console/termination/status/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package status

import (
workloadsv1alpha1 "github.com/gocardless/theatre/v3/apis/workloads/v1alpha1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func UpdateStatus(c client.Client, instance *workloadsv1alpha1.Console, result *Result) error {
return nil
}
13 changes: 13 additions & 0 deletions controllers/workloads/console/termination/status/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package status

import (
workloadsv1alpha1 "github.com/gocardless/theatre/v3/apis/workloads/v1alpha1"
)

// Result is the basis for updating the status of a Console with termination
// events
type Result struct {
Phase *workloadsv1alpha1.ConsolePhase
Condition workloadsv1alpha1.ConsoleConditionType
Reason workloadsv1alpha1.ConsoleConditionReason
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package termination

import (
"context"
"fmt"

workloadsv1alpha1 "github.com/gocardless/theatre/v3/apis/workloads/v1alpha1"

"github.com/gocardless/theatre/v3/controllers/workloads/console/termination/handler"
"github.com/gocardless/theatre/v3/controllers/workloads/console/termination/status"
batchv1 "k8s.io/api/batch/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
watchhandler "sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)

// newReconciler returns a new reconcile.Reconciler
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
h := handler.NewTerminationHandler(mgr.GetClient(), &handler.Options{})
return &TerminationReconciler{Client: mgr.GetClient(), handler: h, scheme: mgr.GetScheme()}
}

func add(mgr manager.Manager, r reconcile.Reconciler) error {
// create the controller
c, err := controller.New("console-termination-controller", mgr, controller.Options{Reconciler: r})
if err != nil {
return err
}

// Watch for Console changes
err = c.Watch(&source.Kind{Type: &workloadsv1alpha1.Console{}}, &watchhandler.EnqueueRequestForOwner{
IsController: true,
})
if err != nil {
return nil
}

// Watch for job changes
err = c.Watch(&source.Kind{Type: &batchv1.Job{}}, &watchhandler.EnqueueRequestForOwner{
OwnerType: &workloadsv1alpha1.Console{},
IsController: true,
})
if err != nil {
return nil
}

// err = mgr.GetCache().IndexField(&batchv1.Job{}, "metadata.labels" ,func(obj runtime.Object) []string

return nil
}

var _ reconcile.Reconciler = &TerminationReconciler{}

type TerminationReconciler struct {
client.Client
handler *handler.TerminationHandler
scheme *runtime.Scheme
}

func (r *TerminationReconciler) SetupWithManager(ctx context.Context, mgr manager.Manager) error {
return add(mgr, newReconciler(mgr))
}

func (r *TerminationReconciler) Reconcile(request reconcile.Request) (reconcile.Result, error) {
instance := &workloadsv1alpha1.Console{}
err := r.Get(context.Background(), request.NamespacedName, instance)
if err != nil {
if errors.IsNotFound(err) {
return reconcile.Result{}, nil
}
return reconcile.Result{}, err
}

result, err := r.handler.Handle(instance)
if err != nil {
statusErr := status.UpdateStatus(r.Client, instance, result)
if statusErr != nil {
// todo: logging good
panic("failed to update status")
}

return reconcile.Result{}, fmt.Errorf("error handling console %s: %v", instance.GetName(), err)
}

err = status.UpdateStatus(r.Client, instance, result)
if err != nil {
return reconcile.Result{}, fmt.Errorf("error updating status: %v", err)
}
return reconcile.Result{}, nil
}

0 comments on commit c9d7cc6

Please sign in to comment.