aboutsummaryrefslogtreecommitdiffstats
path: root/src/monitor/pkg/controller/resourcebundlestate/controller.go
blob: debd5f65a50a50c82f8c58d7055c389285b9e9a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package resourcebundlestate

import (
	"context"
	"log"

	"monitor/pkg/apis/k8splugin/v1alpha1"

	corev1 "k8s.io/api/core/v1"
	k8serrors "k8s.io/apimachinery/pkg/api/errors"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	"sigs.k8s.io/controller-runtime/pkg/source"
)

// Add the new controller to the controller manager
func Add(mgr manager.Manager) error {
	return add(mgr, newReconciler(mgr))
}

func add(mgr manager.Manager, r *reconciler) error {
	// Create a new controller
	c, err := controller.New("ResourceBundleState-controller", mgr, controller.Options{Reconciler: r})
	if err != nil {
		return err
	}

	// Watch for changes to primary resource ResourceBundleState
	err = c.Watch(&source.Kind{Type: &v1alpha1.ResourceBundleState{}}, &EventHandler{})
	if err != nil {
		return err
	}

	return nil
}

func newReconciler(m manager.Manager) *reconciler {
	return &reconciler{client: m.GetClient()}
}

type reconciler struct {
	// Stores an array of all the ResourceBundleState
	crList []v1alpha1.ResourceBundleState
	client client.Client
}

// Reconcile implements the loop that will manage the ResourceBundleState CR
// We only accept CREATE events here and any subsequent changes are ignored.
func (r *reconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
	log.Printf("Reconciling ResourceBundleState %+v\n", req)

	rbstate := &v1alpha1.ResourceBundleState{}
	err := r.client.Get(context.TODO(), req.NamespacedName, rbstate)
	if err != nil {
		if k8serrors.IsNotFound(err) {
			log.Printf("Object not found: %+v. Ignore as it must have been deleted.\n", req.NamespacedName)
			return reconcile.Result{}, nil
		}
		log.Printf("Failed to get object: %+v\n", req.NamespacedName)
		return reconcile.Result{}, err
	}

	err = r.updatePods(rbstate, rbstate.Spec.Selector.MatchLabels)
	if err != nil {
		log.Printf("Error adding podstatuses: %v\n", err)
		return reconcile.Result{}, err
	}

	err = r.updateServices(rbstate, rbstate.Spec.Selector.MatchLabels)
	if err != nil {
		log.Printf("Error adding services: %v\n", err)
		return reconcile.Result{}, err
	}

	// TODO: Update this based on the statuses of the lower resources
	rbstate.Status.Ready = false
	err = r.client.Status().Update(context.TODO(), rbstate)
	if err != nil {
		log.Printf("failed to update rbstate: %v\n", err)
		return reconcile.Result{}, err
	}

	return reconcile.Result{}, nil
}

func (r *reconciler) updateServices(rbstate *v1alpha1.ResourceBundleState,
	selectors map[string]string) error {

	// Update the CR with the Services created as well
	serviceList := &corev1.ServiceList{}
	err := listResources(r.client, rbstate.Namespace, selectors, serviceList)
	if err != nil {
		log.Printf("Failed to list services: %v", err)
		return err
	}

	rbstate.Status.ServiceStatuses = serviceList.Items
	return nil
}

func (r *reconciler) updatePods(rbstate *v1alpha1.ResourceBundleState,
	selectors map[string]string) error {

	// Update the CR with the pods tracked
	podList := &corev1.PodList{}
	err := listResources(r.client, rbstate.Namespace, selectors, podList)
	if err != nil {
		log.Printf("Failed to list pods: %v", err)
		return err
	}

	rbstate.Status.PodStatuses = []v1alpha1.PodStatus{}

	for _, pod := range podList.Items {
		resStatus := v1alpha1.PodStatus{
			ObjectMeta: pod.ObjectMeta,
			Ready:      false,
			Status:     pod.Status,
		}
		rbstate.Status.PodStatuses = append(rbstate.Status.PodStatuses, resStatus)
	}

	return nil
}