Skip to content

Commit

Permalink
update to controller-runtime 0.18.3
Browse files Browse the repository at this point in the history
  • Loading branch information
xrstf committed May 27, 2024
1 parent e72bede commit 1b70e57
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 132 deletions.
8 changes: 0 additions & 8 deletions deploy/rbac-controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,6 @@ rules:
- list
- get
- watch
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
Expand Down
16 changes: 7 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ require (
go.uber.org/zap v1.27.0
gopkg.in/yaml.v3 v3.0.1
k8c.io/reconciler v0.5.0
k8s.io/api v0.30.0
k8s.io/apimachinery v0.30.0
k8s.io/client-go v0.30.0
k8s.io/code-generator v0.30.0
k8s.io/api v0.30.1
k8s.io/apimachinery v0.30.1
k8s.io/client-go v0.30.1
k8s.io/code-generator v0.30.1
k8s.io/klog/v2 v2.120.1
k8s.io/utils v0.0.0-20240310230437-4693a0247e57
// Pinned due to a breaking change in k8s.io/client-go/tools/leaderelection in v0.30.0
// TODO: Update to the latest semver version when https://github.com/kubernetes-sigs/controller-runtime/pull/2693 is released
sigs.k8s.io/controller-runtime v0.17.1-0.20240418082203-04706074d2f1
sigs.k8s.io/controller-runtime v0.18.3
sigs.k8s.io/controller-tools v0.14.0
sigs.k8s.io/yaml v1.4.0
)
Expand Down Expand Up @@ -101,8 +99,8 @@ require (
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/apiextensions-apiserver v0.30.0-rc.2 // indirect
k8s.io/component-base v0.30.0-rc.2 // indirect
k8s.io/apiextensions-apiserver v0.30.1 // indirect
k8s.io/component-base v0.30.1 // indirect
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 // indirect
k8s.io/klog v1.0.0 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
Expand Down
28 changes: 14 additions & 14 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -502,18 +502,18 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8c.io/reconciler v0.5.0 h1:BHpelg1UfI/7oBFctqOq8sX6qzflXpl3SlvHe7e8wak=
k8c.io/reconciler v0.5.0/go.mod h1:pT1+SVcVXJQeBJhpJBXQ5XW64QnKKeYTnVlQf0dGE0k=
k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA=
k8s.io/api v0.30.0/go.mod h1:OPlaYhoHs8EQ1ql0R/TsUgaRPhpKNxIMrKQfWUp8QSE=
k8s.io/apiextensions-apiserver v0.30.0-rc.2 h1:nnQg+c72aanAIrrPSyds0jtazCjOQDHo2vpazxem/TI=
k8s.io/apiextensions-apiserver v0.30.0-rc.2/go.mod h1:Vfet39CooU8WJYMintiVVNCJhHHtiJ/+ZX3CgA7O+so=
k8s.io/apimachinery v0.30.0 h1:qxVPsyDM5XS96NIh9Oj6LavoVFYff/Pon9cZeDIkHHA=
k8s.io/apimachinery v0.30.0/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
k8s.io/client-go v0.30.0 h1:sB1AGGlhY/o7KCyCEQ0bPWzYDL0pwOZO4vAtTSh/gJQ=
k8s.io/client-go v0.30.0/go.mod h1:g7li5O5256qe6TYdAMyX/otJqMhIiGgTapdLchhmOaY=
k8s.io/code-generator v0.30.0 h1:3VUVqHvWFSVSm9kqL/G6kD4ZwNdHF6J/jPyo3Jgjy3k=
k8s.io/code-generator v0.30.0/go.mod h1:mBMZhfRR4IunJUh2+7LVmdcWwpouCH5+LNPkZ3t/v7Q=
k8s.io/component-base v0.30.0-rc.2 h1:0Qa6faUg01rBp9VxU76B8PmK58rBcAGB+7r4ckpLtgI=
k8s.io/component-base v0.30.0-rc.2/go.mod h1:rdQm+7+FBi+t74zJKiKBYVgQJEiNRMqvESRh8/f5z5k=
k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY=
k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM=
k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws=
k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4=
k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U=
k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q=
k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc=
k8s.io/code-generator v0.30.1 h1:ZsG++q5Vt0ScmKCeLhynUuWgcwFGg1Hl1AGfatqPJBI=
k8s.io/code-generator v0.30.1/go.mod h1:hFgxRsvOUg79mbpbVKfjJvRhVz1qLoe40yZDJ/hwRH4=
k8s.io/component-base v0.30.1 h1:bvAtlPh1UrdaZL20D9+sWxsJljMi0QZ3Lmw+kmZAaxQ=
k8s.io/component-base v0.30.1/go.mod h1:e/X9kDiOebwlI41AvBHuWdqFriSRrX50CdwA9TFaHLI=
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 h1:NGrVE502P0s0/1hudf8zjgwki1X/TByhmAoILTarmzo=
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
Expand All @@ -529,8 +529,8 @@ k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/controller-runtime v0.17.1-0.20240418082203-04706074d2f1 h1:W15Y5zHVUsH1YJvstRqy6lG0KquU7kS2ooGC5poLnrU=
sigs.k8s.io/controller-runtime v0.17.1-0.20240418082203-04706074d2f1/go.mod h1:umEFUKWCSYpq2U4tNN7riBXU6iiulk7bdF0XZq9LzvU=
sigs.k8s.io/controller-runtime v0.18.3 h1:B5Wmmo8WMWK7izei+2LlXLVDGzMwAHBNLX68lwtlSR4=
sigs.k8s.io/controller-runtime v0.18.3/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg=
sigs.k8s.io/controller-tools v0.14.0 h1:rnNoCC5wSXlrNoBKKzL70LNJKIQKEzT6lloG6/LF73A=
sigs.k8s.io/controller-tools v0.14.0/go.mod h1:TV7uOtNNnnR72SpzhStvPkoS/U5ir0nMudrkrC4M9Sc=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
Expand Down
21 changes: 10 additions & 11 deletions pkg/controllers/osc/osc_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,12 @@ import (
"k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/tools/record"
ctrlruntime "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)

const (
Expand Down Expand Up @@ -121,21 +120,21 @@ func Add(
nodeRegistryCredentialsSecret: nodeRegistryCredentialsSecret,
kubeletFeatureGates: kubeletFeatureGates,
}
c, err := controller.New(ControllerName, mgr, controller.Options{Reconciler: reconciler, MaxConcurrentReconciles: workerCount})
if err != nil {
return err
}

if err := c.Watch(source.Kind(mgr.GetCache(), &clusterv1alpha1.MachineDeployment{}), &handler.EnqueueRequestForObject{}, filterMachineDeploymentPredicate()); err != nil {
return fmt.Errorf("failed to watch MachineDeployments: %w", err)
}
_, err := builder.ControllerManagedBy(mgr).
Named(ControllerName).
WithOptions(controller.Options{
MaxConcurrentReconciles: workerCount,
}).
For(&clusterv1alpha1.MachineDeployment{}, builder.WithPredicates(filterMachineDeploymentPredicate())).
Build(reconciler)

return nil
return err
}

func (r *Reconciler) Reconcile(ctx context.Context, req ctrlruntime.Request) (reconcile.Result, error) {
log := r.log.With("request", req)
log.Info("Reconciling OSC resource..")
log.Debug("Reconciling OSC resource...")

machineDeployment := &clusterv1alpha1.MachineDeployment{}
if err := r.workerClient.Get(ctx, req.NamespacedName, machineDeployment); err != nil {
Expand Down
175 changes: 85 additions & 90 deletions pkg/controllers/osp/osp_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package osp
import (
"context"
"fmt"
"io/fs"
"path/filepath"
"strings"

Expand All @@ -28,13 +27,11 @@ import (
"k8c.io/operating-system-manager/deploy/osps"
"k8c.io/operating-system-manager/pkg/crd/osm/v1alpha1"
"k8c.io/operating-system-manager/pkg/resources/reconciling"
predicateutil "k8c.io/operating-system-manager/pkg/util/predicate"

appsv1 "k8s.io/api/apps/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
yamlutil "k8s.io/apimachinery/pkg/util/yaml"
ctrlruntime "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/event"
Expand All @@ -51,132 +48,130 @@ const (
ospsDefaultDirName = "default"
)

type ospMap map[string]*v1alpha1.OperatingSystemProfile

type Reconciler struct {
client.Client
log *zap.SugaredLogger
defaultOSPFiles map[string][]byte
log *zap.SugaredLogger
defaultOSPs ospMap

namespace string
}

func Add(mgr manager.Manager, log *zap.SugaredLogger, namespace string, workerCount int) error {
ospDefaultDir, err := osps.FS.ReadDir(ospsDefaultDirName)
defaultOSPs, err := loadDefaultOSPs()
if err != nil {
return fmt.Errorf("failed to read osps default directory: %w", err)
return fmt.Errorf("failed to load default OSPs: %w", err)
}

var defaultOSPFiles = make(map[string][]byte, len(ospDefaultDir))
for _, ospFile := range ospDefaultDir {
defaultOSPFile, err := fs.ReadFile(osps.FS, filepath.Join(ospsDefaultDirName, ospFile.Name()))
if err != nil {
return fmt.Errorf("failed to read osp file %s: %w", ospFile.Name(), err)
reconciler := &Reconciler{
Client: mgr.GetClient(),
log: log,
defaultOSPs: defaultOSPs,
namespace: namespace,
}

// trigger controller once upon startup to bootstrap the default OSPs
bootstrapping := make(chan event.GenericEvent, len(defaultOSPs))
for name := range defaultOSPs {
bootstrapping <- event.GenericEvent{
Object: &v1alpha1.OperatingSystemProfile{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
},
}
}

defaultOSPFiles[ospFile.Name()] = defaultOSPFile
_, err = builder.ControllerManagedBy(mgr).
Named(ControllerName).
WithOptions(controller.Options{
MaxConcurrentReconciles: workerCount,
}).
For(&v1alpha1.OperatingSystemProfile{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
return object.GetNamespace() == namespace
}))).
WatchesRawSource(source.Channel(bootstrapping, &handler.EnqueueRequestForObject{})).
Build(reconciler)

return err
}

func (r *Reconciler) Reconcile(ctx context.Context, req ctrlruntime.Request) (reconcile.Result, error) {
if err := r.reconcileOSP(ctx, req.Name); err != nil {
return reconcile.Result{}, err
}

reconciler := &Reconciler{
Client: mgr.GetClient(),
log: log,
defaultOSPFiles: defaultOSPFiles,
namespace: namespace,
return reconcile.Result{}, nil
}

func (r *Reconciler) reconcileOSP(ctx context.Context, name string) error {
osp, ok := r.defaultOSPs[name]
if !ok {
return nil
}

c, err := controller.New(ControllerName, mgr, controller.Options{Reconciler: reconciler, MaxConcurrentReconciles: workerCount})
if err != nil {
return err
r.log.Debugw("Reconciling OSP resource...", "osp", name)

ospReconcilers := []reconciling.NamedOperatingSystemProfileReconcilerFactory{
ospReconciler(name, osp),
}

// Since the osp controller cares about only creating the default OSP resources, we need to watch for the creation
// of any random resource in the underlying namespace where osm is deployed. We picked deployments for this and added additional
// event filtering to avoid redundant reconciliation/requeues.
if err := c.Watch(source.Kind(mgr.GetCache(), &appsv1.Deployment{}),
&handler.EnqueueRequestForObject{},
filterDeploymentPredicate(),
predicateutil.ByNamespace(namespace),
); err != nil {
return fmt.Errorf("failed to create watch for deployments: %w", err)
if err := reconciling.ReconcileOperatingSystemProfiles(ctx, ospReconcilers, r.namespace, r.Client); err != nil {
return fmt.Errorf("failed to reconcile OSP: %w", err)
}

return nil
}

func (r *Reconciler) Reconcile(ctx context.Context, _ ctrlruntime.Request) (reconcile.Result, error) {
r.log.Info("Reconciling default OSP resource..")
func ospReconciler(name string, source *v1alpha1.OperatingSystemProfile) reconciling.NamedOperatingSystemProfileReconcilerFactory {
return func() (string, reconciling.OperatingSystemProfileReconciler) {
return name, func(osp *v1alpha1.OperatingSystemProfile) (*v1alpha1.OperatingSystemProfile, error) {
// only attempt an update if our OSP is newer
if osp.Spec.Version != source.Spec.Version {
osp.Spec = source.Spec
}

if err := r.reconcile(ctx); err != nil {
return reconcile.Result{}, err
return osp, nil
}
}
return reconcile.Result{}, nil
}

func (r *Reconciler) reconcile(ctx context.Context) error {
var ospReconcilers []reconciling.NamedOperatingSystemProfileReconcilerFactory
for name, ospFile := range r.defaultOSPFiles {
osp, err := parseYAMLToObject(ospFile)
if err != nil {
return fmt.Errorf("failed to parse osp %s: %w", name, err)
}
func loadDefaultOSPs() (ospMap, error) {
ospDefaultDir, err := osps.FS.ReadDir(ospsDefaultDirName)
if err != nil {
return nil, fmt.Errorf("failed to read OSPs default directory: %w", err)
}

// Remove file extension .yaml from the OSP name
name = strings.ReplaceAll(name, ".yaml", "")
var defaultOSPs = make(ospMap, len(ospDefaultDir))
for _, ospFile := range ospDefaultDir {
filename := ospFile.Name()

// Check if OSP already exists
existingOSP := &v1alpha1.OperatingSystemProfile{}
if err := r.Client.Get(ctx, types.NamespacedName{Name: name, Namespace: r.namespace}, existingOSP); err != nil && !kerrors.IsNotFound(err) {
return fmt.Errorf("failed to retrieve existing OperatingSystemProfile: %w", err)
osp, err := parseOSPFile(filename)
if err != nil {
return nil, fmt.Errorf("failed to read OSP %s: %w", filename, err)
}

// Since OSPs are immutable, we only want to reconcile resources when the version is different.
if osp.Spec.Version != existingOSP.Spec.Version {
// OSP already exists
osp.SetResourceVersion(existingOSP.GetResourceVersion())
osp.SetGeneration(existingOSP.GetGeneration())

ospReconcilers = append(ospReconcilers, ospReconciler(name, osp))
}
}
// Remove file extension .yaml to get OSP name
ospName := strings.ReplaceAll(filename, ".yaml", "")

if err := reconciling.ReconcileOperatingSystemProfiles(ctx,
ospReconcilers,
r.namespace, r.Client); err != nil {
return fmt.Errorf("failed to reconcile osps: %w", err)
defaultOSPs[ospName] = osp
}

return nil
return defaultOSPs, nil
}

func ospReconciler(name string, osp *v1alpha1.OperatingSystemProfile) reconciling.NamedOperatingSystemProfileReconcilerFactory {
return func() (string, reconciling.OperatingSystemProfileReconciler) {
return name, func(*v1alpha1.OperatingSystemProfile) (*v1alpha1.OperatingSystemProfile, error) {
return osp, nil
}
func parseOSPFile(filename string) (*v1alpha1.OperatingSystemProfile, error) {
content, err := osps.FS.ReadFile(filepath.Join(ospsDefaultDirName, filename))
if err != nil {
return nil, err
}
}

func parseYAMLToObject(ospByte []byte) (*v1alpha1.OperatingSystemProfile, error) {
osp := &v1alpha1.OperatingSystemProfile{}
if err := yamlutil.Unmarshal(ospByte, osp); err != nil {
if err := yamlutil.Unmarshal(content, osp); err != nil {
return nil, err
}

return osp, nil
}

// filterDeploymentPredicate filters out all deployment events except the creation one.
func filterDeploymentPredicate() predicate.Predicate {
return predicate.Funcs{
CreateFunc: func(_ event.CreateEvent) bool {
return true
},
DeleteFunc: func(_ event.DeleteEvent) bool {
return false
},
UpdateFunc: func(_ event.UpdateEvent) bool {
return false
},
GenericFunc: func(_ event.GenericEvent) bool {
return false
},
}
}

0 comments on commit 1b70e57

Please sign in to comment.