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

feat: recursive expansion #2679

Merged
merged 13 commits into from
May 10, 2023
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
contrib.go.opencensus.io/exporter/prometheus v0.4.2
contrib.go.opencensus.io/exporter/stackdriver v0.13.14
github.com/davecgh/go-spew v1.1.1
github.com/dominikbraun/graph v0.16.2
github.com/ghodss/yaml v1.0.0
github.com/go-logr/logr v1.2.4
github.com/go-logr/zapr v1.2.3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,8 @@ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arX
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dominikbraun/graph v0.16.2 h1:EUndsCgHNQDHBdT4Q4M9GBePH3Tt0sV7DDPVWzfbEh4=
github.com/dominikbraun/graph v0.16.2/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
Expand Down
71 changes: 66 additions & 5 deletions pkg/controller/expansion/expansion_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
"github.com/open-policy-agent/gatekeeper/apis/expansion/unversioned"
"github.com/open-policy-agent/gatekeeper/apis/expansion/v1alpha1"
expansionv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/expansion/v1alpha1"
"github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
statusv1beta1 "github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
"github.com/open-policy-agent/gatekeeper/pkg/expansion"
Expand All @@ -20,10 +21,12 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
Expand All @@ -33,6 +36,9 @@ import (

var log = logf.Log.WithName("controller").WithValues("kind", "ExpansionTemplate", logging.Process, "template_expansion_controller")

// eventQueueSize is how many events to queue before blocking.
const eventQueueSize = 1024

type Adder struct {
WatchManager *watch.Manager
ExpansionSystem *expansion.System
Expand Down Expand Up @@ -78,11 +84,18 @@ type Reconciler struct {
registry *etRegistry
statusClient client.StatusClient
tracker *readiness.Tracker
events chan event.GenericEvent
eventSource source.Source

getPod func(context.Context) (*corev1.Pod, error)
}

func newReconciler(mgr manager.Manager, system *expansion.System, getPod func(ctx context.Context) (*corev1.Pod, error), tracker *readiness.Tracker) *Reconciler {
func newReconciler(mgr manager.Manager,
system *expansion.System,
getPod func(ctx context.Context) (*corev1.Pod, error),
tracker *readiness.Tracker,
) *Reconciler {
ev := make(chan event.GenericEvent, eventQueueSize)
return &Reconciler{
Client: mgr.GetClient(),
system: system,
Expand All @@ -91,23 +104,36 @@ func newReconciler(mgr manager.Manager, system *expansion.System, getPod func(ct
statusClient: mgr.GetClient(),
getPod: getPod,
tracker: tracker,
events: ev,
eventSource: &source.Channel{Source: ev, DestBufferSize: 1024},
}
}

func add(mgr manager.Manager, r reconcile.Reconciler) error {
func add(mgr manager.Manager, r *Reconciler) error {
c, err := controller.New("expansion-template-controller", mgr, controller.Options{Reconciler: r})
if err != nil {
return err
}

// Watch for enqueued events
if r.eventSource != nil {
err = c.Watch(
r.eventSource,
&handler.EnqueueRequestForObject{})
if err != nil {
return err
}
}

// Watch for changes to ExpansionTemplates
return c.Watch(
&source.Kind{Type: &v1alpha1.ExpansionTemplate{}},
&handler.EnqueueRequestForObject{})
}

func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
defer r.registry.report(ctx)
log.Info("Reconcile", "request", request, "namespace", request.Namespace, "name", request.Name)
log.V(logging.DebugLevel).Info("Reconcile", "request", request, "namespace", request.Namespace, "name", request.Name)
davis-haba marked this conversation as resolved.
Show resolved Hide resolved

deleted := false
versionedET := &v1alpha1.ExpansionTemplate{}
Expand All @@ -123,6 +149,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
if err := r.scheme.Convert(versionedET, et, nil); err != nil {
return reconcile.Result{}, err
}
oldConflicts := r.system.GetConflicts()

if !et.GetDeletionTimestamp().IsZero() {
deleted = true
}

if deleted {
// et will be an empty struct. We set the metadata name, which is
Expand All @@ -132,9 +163,10 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
r.getTracker().TryCancelExpect(versionedET)
return reconcile.Result{}, err
}
log.Info("removed expansion template", "template name", et.GetName())
log.V(logging.DebugLevel).Info("removed expansion template", "template name", et.GetName())
r.registry.remove(request.NamespacedName)
r.getTracker().CancelExpect(versionedET)
r.queueConflicts(oldConflicts)
return reconcile.Result{}, r.deleteStatus(ctx, request.NamespacedName.Name)
}

Expand All @@ -149,9 +181,38 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
log.Error(upsertErr, "upserting template", "template_name", et.GetName())
}

r.queueConflicts(oldConflicts)
return reconcile.Result{}, r.updateOrCreatePodStatus(ctx, et, upsertErr)
}

func (r *Reconciler) queueConflicts(old expansion.IDSet) {
for tID := range symmetricDiff(old, r.system.GetConflicts()) {
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(expansionv1alpha1.GroupVersion.WithKind("ExpansionTemplate"))
// ExpansionTemplate is cluster-scoped, so we do not set namespace
u.SetName(string(tID))

r.events <- event.GenericEvent{Object: u}
}
}

func symmetricDiff(x, y expansion.IDSet) expansion.IDSet {
sDiff := make(expansion.IDSet)

for id := range x {
if _, exists := y[id]; !exists {
sDiff[id] = true
}
}
for id := range y {
if _, exists := x[id]; !exists {
sDiff[id] = true
}
}

return sDiff
}

func (r *Reconciler) deleteStatus(ctx context.Context, etName string) error {
status := &v1beta1.ExpansionTemplatePodStatus{}
pod, err := r.getPod(ctx)
Expand Down Expand Up @@ -227,5 +288,5 @@ func setStatusError(status *v1beta1.ExpansionTemplatePodStatus, etErr error) {
}

e := &v1beta1.ExpansionTemplateError{Message: etErr.Error()}
status.Status.Errors = append(status.Status.Errors, e)
status.Status.Errors = []*statusv1beta1.ExpansionTemplateError{e}
davis-haba marked this conversation as resolved.
Show resolved Hide resolved
}