Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] WINC-897: React to kubelet arg changes #2483

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions controllers/configmap_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"strings"

config "github.com/openshift/api/config/v1"
mcfgv1 "github.com/openshift/api/machineconfiguration/v1"
core "k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
k8sapierrors "k8s.io/apimachinery/pkg/api/errors"
Expand Down Expand Up @@ -186,7 +187,18 @@ func (r *ConfigMapReconciler) Reconcile(ctx context.Context,
// At this point configMap will be set properly
switch req.NamespacedName.Name {
case servicescm.Name:
return ctrl.Result{}, r.reconcileServices(ctx, configMap)
// get the machineConfig

if nodename, ok := ctx.Value("nodename").(string); ok {
node := &core.Node{}
if err := r.client.Get(ctx, kubeTypes.NamespacedName{
Name: nodename},
node); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, r.reconcileServices(ctx, configMap, node)
}

case wiparser.InstanceConfigMap:
return ctrl.Result{}, r.reconcileNodes(ctx, configMap)
case certificates.ProxyCertsConfigMap:
Expand All @@ -200,7 +212,7 @@ func (r *ConfigMapReconciler) Reconcile(ctx context.Context,

// reconcileServices uses the data within the services ConfigMap to ensure WMCO-managed Windows services on
// Windows Nodes have the expected configuration and are in the expected state
func (r *ConfigMapReconciler) reconcileServices(ctx context.Context, windowsServices *core.ConfigMap) error {
func (r *ConfigMapReconciler) reconcileServices(ctx context.Context, windowsServices *core.ConfigMap, node *core.Node) error {
if err := r.removeOutdatedServicesConfigMaps(ctx); err != nil {
return err
}
Expand All @@ -216,6 +228,16 @@ func (r *ConfigMapReconciler) reconcileServices(ctx context.Context, windowsServ
kubeTypes.NamespacedName{Namespace: r.watchNamespace, Name: windowsServices.Name}, "Error", err.Error())
return nil
}
// machineconfig.Spec.Config
// unmarshal the json, and set the data to the machineconfig's value

for key, value := range data.Services {
r.log.Info("configmap data: Key", key, " Value: ", value)
}

// for each in node.Annotations
// for each in node.Labels

// TODO: actually react to changes to the services ConfigMap
return nil
}
Expand Down Expand Up @@ -386,7 +408,21 @@ func (r *ConfigMapReconciler) mapToInstancesConfigMap(_ context.Context, _ clien
}

// mapToServicesConfigMap fulfills the MapFn type, while always returning a request to the windows-services ConfigMap
func (r *ConfigMapReconciler) mapToServicesConfigMap(_ context.Context, _ client.Object) []reconcile.Request {
func (r *ConfigMapReconciler) mapToServicesConfigMap(ctx context.Context, obj client.Object) []reconcile.Request {
switch resource := obj.(type) {
case *core.Node:
nodeName := resource.GetName()
ctx = context.WithValue(ctx, "nodename", nodeName)
r.log.Info("change triggered by node", "node", nodeName)
case *mcfgv1.MachineConfig:
machineconfigname := resource.GetName()
ctx = context.WithValue(ctx, "machineconfigname", machineconfigname)
r.log.Info("change triggered my machineconfig", "machineconfig", machineconfigname)
default:
r.log.Info("unknown object type")
return nil
}

return []reconcile.Request{{
NamespacedName: kubeTypes.NamespacedName{Namespace: r.watchNamespace, Name: servicescm.Name},
}}
Expand Down Expand Up @@ -414,6 +450,12 @@ func (r *ConfigMapReconciler) SetupWithManager(mgr ctrl.Manager) error {
builder.WithPredicates(outdatedWindowsNodePredicate(true))).
Watches(&core.Node{}, handler.EnqueueRequestsFromMapFunc(r.mapToServicesConfigMap),
builder.WithPredicates(windowsNodeVersionChangePredicate())).
Watches(&core.Node{}, handler.EnqueueRequestsFromMapFunc(r.mapToServicesConfigMap),
builder.WithPredicates(nodeLabelChangedPredicate())).
Watches(&core.Node{}, handler.EnqueueRequestsFromMapFunc(r.mapToServicesConfigMap),
builder.WithPredicates(nodeconfigChangedPredicate())).
Comment on lines +453 to +456
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can consolidate this into 1 by creating a smarter predicate func

Copy link
Contributor

@saifshaikh48 saifshaikh48 Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please explain why this watch is needed as well. Do we use node annotations to create (or modify) kubelet args? If so, please point to where we do that because i can't find where in our code

Watches(&mcfgv1.MachineConfig{}, handler.EnqueueRequestsFromMapFunc(r.mapToServicesConfigMap),
builder.WithPredicates(machineConfigChangedPredicate())).
Complete(r)
}

Expand Down
96 changes: 96 additions & 0 deletions controllers/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"context"
"fmt"
"net"
"reflect"
"sync"

"github.com/go-logr/logr"
config "github.com/openshift/api/config/v1"
mcfgv1 "github.com/openshift/api/machineconfiguration/v1"
"golang.org/x/crypto/ssh"
core "k8s.io/api/core/v1"
kubeTypes "k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -201,6 +203,100 @@ func windowsNodeVersionChangePredicate() predicate.Funcs {
}
}

func nodeLabelChangedPredicate() predicate.Funcs {
return predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
return false
},
UpdateFunc: func(e event.UpdateEvent) bool {
// check if node object metadata.labels = e.objectold vs e.objectnew
return !reflect.DeepEqual(e.ObjectOld.GetLabels(), e.ObjectNew.GetLabels())
},
GenericFunc: func(e event.GenericEvent) bool {
return false

},
DeleteFunc: func(e event.DeleteEvent) bool {
return false
},
}
}

func machineConfigChangedPredicate() predicate.Funcs {
return predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
return false
},
UpdateFunc: func(e event.UpdateEvent) bool {
oldMachineConfig, _ := e.ObjectOld.(*mcfgv1.MachineConfig)
newMachineConfig, _ := e.ObjectNew.(*mcfgv1.MachineConfig)

if !reflect.DeepEqual(oldMachineConfig.Spec.Config, newMachineConfig.Spec.Config) {
return true
}

return false

// check if any of the machineconfig attributes have changed
//
//Config
//Bootstrap-kubeconfig
//Kubeconfig
//Container-runtime
//Container-runtime-endpoint
//Runtime-cgroups
//Node-ip
//Volume-plugin-dir
//Cloud-provider
//Cloud-config
//Hostname-override
//Provider-id
//Pod-infra-container-image
//System-reserved
},
GenericFunc: func(e event.GenericEvent) bool {
return false

},
DeleteFunc: func(e event.DeleteEvent) bool {
return false
},
}
}

func nodeconfigChangedPredicate() predicate.Funcs {
return predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
return false
},
UpdateFunc: func(e event.UpdateEvent) bool {
oldNode, _ := e.ObjectOld.(*core.Node)
newNode, _ := e.ObjectNew.(*core.Node)

// Check if "Node-ip" label has changed
if oldNode.Labels["Node-ip"] != newNode.Labels["Node-ip"] {
return true
}

// Check if "Hostname-override" label has changed
if oldNode.Labels["Hostname-override"] != newNode.Labels["Hostname-override"] {
return true
}
// check if nodeconfig has any attributes that have changed
//
// Node-ip
// Hostname-override
return false
},
GenericFunc: func(e event.GenericEvent) bool {
return false
},
DeleteFunc: func(e event.DeleteEvent) bool {
return false
},
}
}

// outdatedWindowsNodePredicate returns a predicate which filters out all node objects that are not up-to-date Windows
// nodes. Up-to-date refers to the version annotation and public key hash annotations.
// If BYOH is true, only BYOH nodes will be allowed through, else no BYOH nodes will be allowed.
Expand Down