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: add syncset controller, feat: syncset readiness #3030

Merged
merged 47 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e34eed0
add syncset controller
acpana Oct 2, 2023
3d43814
add syncset readiness, observe config
acpana Oct 3, 2023
0dc69bd
reconcile data expectations
acpana Oct 3, 2023
46dfde2
enable syncset crd
acpana Oct 3, 2023
686af5d
interpret registrar err
acpana Oct 5, 2023
7e94cdd
review: move EM, rename to EP
acpana Oct 5, 2023
31979ac
review: remove waitgroup
acpana Oct 6, 2023
b290867
smoll fix for test
acpana Oct 7, 2023
49d652e
Merge branch 'master' into acpana/syncsets-rt-r
acpana Oct 9, 2023
2192d65
use logging constant
acpana Oct 9, 2023
592e243
add TryCancelData
acpana Oct 9, 2023
8da842c
fix lock
acpana Oct 9, 2023
50f7abd
review: rm comments, mgr starts pruner
acpana Oct 11, 2023
7296196
review: move interface, IsUniversal
acpana Oct 11, 2023
6a260a3
review: explicitly remove source
acpana Oct 11, 2023
a1e153f
Merge branch 'master' into acpana/syncsets-rt-r
acpana Oct 12, 2023
689b252
limit name to 63 char
acpana Oct 13, 2023
4708b4d
review: comments, naming, HasBalidationOperation
acpana Oct 13, 2023
9937605
only add syncset controller for validation
acpana Oct 13, 2023
05af5c9
flesh out errorList
acpana Oct 13, 2023
dda78b6
TryCancel all gvks if universal
acpana Oct 16, 2023
5e48091
review feedback
acpana Oct 19, 2023
24f9237
review feedback
acpana Oct 26, 2023
53a7625
review feedback
acpana Oct 28, 2023
c8537e2
use fake client builder
acpana Oct 29, 2023
7cd0440
use fake client builder in readiness pkg too
acpana Oct 29, 2023
23d9ef7
Merge branch 'master' into acpana/syncsets-rt-r
acpana Oct 30, 2023
c4ea7cb
review feedback
acpana Nov 2, 2023
b660943
review: remove Test_ExpectationsMgr_DeletedSyncSets
acpana Nov 2, 2023
79dce07
refactor: agg err, restore agg
acpana Nov 2, 2023
09842ff
revert: restore agg
acpana Nov 3, 2023
3d07778
revert: infer podGVK
acpana Nov 3, 2023
ccf2160
add RemoveGVKErr
acpana Nov 3, 2023
449b39a
account for dangling watches
acpana Nov 4, 2023
d0ebd6a
better handling for dangling watches
acpana Nov 6, 2023
eeba2bf
check err nullability, naming
acpana Nov 7, 2023
034e826
use remove set instead of forceWipe
acpana Nov 7, 2023
854306e
set instead of book for dangling watches
acpana Nov 9, 2023
d7bb9b5
general error watch dangling
acpana Nov 9, 2023
7faecbc
review feedback
acpana Nov 10, 2023
03565fa
refactor: use tt
acpana Nov 15, 2023
3766d66
fix: general err dangling watches
acpana Nov 15, 2023
352ae72
rf: add set directly
acpana Nov 16, 2023
a216503
Merge branch 'master' into acpana/syncsets-rt-r
acpana Nov 17, 2023
a280fb7
Apply suggestions from code review
acpana Nov 22, 2023
c87e934
review suggestions
acpana Nov 22, 2023
430deea
Merge branch 'master' into acpana/syncsets-rt-r
acpana Nov 22, 2023
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
9 changes: 9 additions & 0 deletions apis/config/v1alpha1/config_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package v1alpha1
import (
"github.com/open-policy-agent/gatekeeper/v3/pkg/wildcard"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

// ConfigSpec defines the desired state of Config.
Expand Down Expand Up @@ -62,6 +63,14 @@ type SyncOnlyEntry struct {
Kind string `json:"kind,omitempty"`
}

func (e *SyncOnlyEntry) ToGroupVersionKind() schema.GroupVersionKind {
return schema.GroupVersionKind{
Group: e.Group,
Version: e.Version,
Kind: e.Kind,
}
}

type MatchEntry struct {
Processes []string `json:"processes,omitempty"`
ExcludedNamespaces []wildcard.Wildcard `json:"excludedNamespaces,omitempty"`
Expand Down
11 changes: 10 additions & 1 deletion apis/syncset/v1alpha1/syncset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

type SyncSetSpec struct {
Expand All @@ -14,10 +15,18 @@ type GVKEntry struct {
Kind string `json:"kind,omitempty"`
}

func (e *GVKEntry) ToGroupVersionKind() schema.GroupVersionKind {
return schema.GroupVersionKind{
Group: e.Group,
Version: e.Version,
Kind: e.Kind,
}
}

// +kubebuilder:resource:scope=Cluster
// +kubebuilder:object:root=true

// SyncSet is the Schema for the SyncSet API.
// SyncSet defines which resources Gatekeeper will cache. The union of all SyncSets plus the syncOnly field of Gatekeeper's Config resource defines the sets of resources that will be synced.
type SyncSet struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
4 changes: 3 additions & 1 deletion config/crd/bases/syncset.gatekeeper.sh_syncsets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ spec:
- name: v1alpha1
schema:
openAPIV3Schema:
description: SyncSet is the Schema for the SyncSet API.
description: SyncSet defines which resources Gatekeeper will cache. The union
of all SyncSets plus the syncOnly field of Gatekeeper's Config resource
defines the sets of resources that will be synced.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
Expand Down
8 changes: 7 additions & 1 deletion config/crd/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# It should be run by config/default
resources:
- bases/config.gatekeeper.sh_configs.yaml
#- bases/syncset.gatekeeper.sh_syncsets.yaml
- bases/syncset.gatekeeper.sh_syncsets.yaml
- bases/status.gatekeeper.sh_constraintpodstatuses.yaml
- bases/status.gatekeeper.sh_constrainttemplatepodstatuses.yaml
- bases/status.gatekeeper.sh_mutatorpodstatuses.yaml
Expand Down Expand Up @@ -56,6 +56,12 @@ patchesJson6902:
kind: CustomResourceDefinition
name: expansiontemplate.expansion.gatekeeper.sh
path: patches/max_name_size.yaml
- target:
group: apiextensions.k8s.io
version: v1
kind: CustomResourceDefinition
name: syncsets.syncset.gatekeeper.sh
path: patches/max_name_size.yaml

patchesStrategicMerge:
#- patches/max_name_size_for_modifyset.yaml
Expand Down
7 changes: 7 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import (
"github.com/open-policy-agent/gatekeeper/v3/pkg/operations"
"github.com/open-policy-agent/gatekeeper/v3/pkg/pubsub"
"github.com/open-policy-agent/gatekeeper/v3/pkg/readiness"
"github.com/open-policy-agent/gatekeeper/v3/pkg/readiness/pruner"
"github.com/open-policy-agent/gatekeeper/v3/pkg/syncutil"
"github.com/open-policy-agent/gatekeeper/v3/pkg/target"
"github.com/open-policy-agent/gatekeeper/v3/pkg/upgrade"
Expand Down Expand Up @@ -486,6 +487,12 @@ func setupControllers(ctx context.Context, mgr ctrl.Manager, sw *watch.Controlle
return err
}

err = mgr.Add(pruner.NewExpectationsPruner(cm, tracker))
if err != nil {
setupLog.Error(err, "adding expectations pruner to manager")
return err
}

opts := controller.Dependencies{
CFClient: client,
WatchManger: wm,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
labels:
gatekeeper.sh/system: "yes"
name: syncsets.syncset.gatekeeper.sh
spec:
group: syncset.gatekeeper.sh
names:
kind: SyncSet
listKind: SyncSetList
plural: syncsets
singular: syncset
preserveUnknownFields: false
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: SyncSet defines which resources Gatekeeper will cache. The union of all SyncSets plus the syncOnly field of Gatekeeper's Config resource defines the sets of resources that will be synced.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
properties:
name:
maxLength: 63
type: string
type: object
spec:
properties:
gvks:
items:
properties:
group:
type: string
kind:
type: string
version:
type: string
type: object
type: array
type: object
type: object
served: true
storage: true
53 changes: 53 additions & 0 deletions manifest_staging/deploy/gatekeeper.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3371,6 +3371,59 @@ spec:
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
labels:
gatekeeper.sh/system: "yes"
name: syncsets.syncset.gatekeeper.sh
spec:
group: syncset.gatekeeper.sh
names:
kind: SyncSet
listKind: SyncSetList
plural: syncsets
singular: syncset
preserveUnknownFields: false
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: SyncSet defines which resources Gatekeeper will cache. The union of all SyncSets plus the syncOnly field of Gatekeeper's Config resource defines the sets of resources that will be synced.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
properties:
name:
maxLength: 63
type: string
type: object
spec:
properties:
gvks:
items:
properties:
group:
type: string
kind:
type: string
version:
type: string
type: object
type: array
type: object
type: object
served: true
storage: true
---
apiVersion: v1
kind: ServiceAccount
metadata:
Expand Down
45 changes: 16 additions & 29 deletions pkg/cachemanager/aggregator/aggregator.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package aggregator

import (
"fmt"
gosync "sync"

"k8s.io/apimachinery/pkg/runtime/schema"
Expand All @@ -10,9 +9,9 @@ import (
// Key defines a type, identifier tuple to store
// in the GVKAggregator.
type Key struct {
// Source specifies the type or where this Key comes from.
// Source specifies the type of the source object.
Source string
// ID specifies the name of the type that this Key is.
// ID specifies the name of the instance of the source object.
ID string
}

Expand Down Expand Up @@ -49,46 +48,39 @@ func (b *GVKAgreggator) IsPresent(gvk schema.GroupVersionKind) bool {
// Remove deletes any associations that Key k has in the GVKAggregator.
// For any GVK in the association k --> [GVKs], we also delete any associations
// between the GVK and the Key k stored in the reverse map.
func (b *GVKAgreggator) Remove(k Key) error {
func (b *GVKAgreggator) Remove(k Key) {
b.mu.Lock()
defer b.mu.Unlock()

gvks, found := b.store[k]
if !found {
return nil
return
}

if err := b.pruneReverseStore(gvks, k); err != nil {
return err
}
b.pruneReverseStore(gvks, k)

delete(b.store, k)
return nil
}

// Upsert stores an association between Key k and the list of GVKs
// and also the reverse associatoin between each GVK passed in and Key k.
acpana marked this conversation as resolved.
Show resolved Hide resolved
// Any old associations are dropped, unless they are included in the new list of
// GVKs.
// It errors out if there is an internal issue with remove the reverse Key links
// for any GVKs that are being dropped as part of this Upsert call.
func (b *GVKAgreggator) Upsert(k Key, gvks []schema.GroupVersionKind) error {
func (b *GVKAgreggator) Upsert(k Key, gvks []schema.GroupVersionKind) {
b.mu.Lock()
defer b.mu.Unlock()

oldGVKs, found := b.store[k]
if found {
// gvksToRemove contains old GKVs that are not included in the new gvks list
gvksToRemove := unreferencedOldGVKsToPrune(gvks, oldGVKs)
if err := b.pruneReverseStore(gvksToRemove, k); err != nil {
return fmt.Errorf("failed to prune entries on upsert: %w", err)
}
b.pruneReverseStore(gvksToRemove, k)
}

// protect against empty inputs
gvksSet := makeSet(gvks)
if len(gvksSet) == 0 {
return nil
return
}

b.store[k] = gvksSet
Expand All @@ -99,19 +91,17 @@ func (b *GVKAgreggator) Upsert(k Key, gvks []schema.GroupVersionKind) error {
}
b.reverseStore[gvk][k] = struct{}{}
}

return nil
}

// List returnes the gvk set for a given Key.
func (b *GVKAgreggator) List(k Key) map[schema.GroupVersionKind]struct{} {
func (b *GVKAgreggator) List(k Key) []schema.GroupVersionKind {
b.mu.RLock()
defer b.mu.RUnlock()

v := b.store[k]
cpy := make(map[schema.GroupVersionKind]struct{}, len(v))
for key, value := range v {
cpy[key] = value
cpy := []schema.GroupVersionKind{}
for key := range v {
cpy = append(cpy, key)
}
return cpy
}
Expand All @@ -128,13 +118,12 @@ func (b *GVKAgreggator) GVKs() []schema.GroupVersionKind {
return allGVKs
}

func (b *GVKAgreggator) pruneReverseStore(gvks map[schema.GroupVersionKind]struct{}, k Key) error {
func (b *GVKAgreggator) pruneReverseStore(gvks map[schema.GroupVersionKind]struct{}, k Key) {
for gvk := range gvks {
keySet, found := b.reverseStore[gvk]
if !found || len(keySet) == 0 {
// this should not happen if we keep the two maps well defined
// but let's be defensive nonetheless.
return fmt.Errorf("internal aggregator error: gvks stores are corrupted for key: %s", k)
if !found {
// by definition, nothing to prune
return
}

delete(keySet, k)
Expand All @@ -146,8 +135,6 @@ func (b *GVKAgreggator) pruneReverseStore(gvks map[schema.GroupVersionKind]struc
b.reverseStore[gvk] = keySet
}
}

return nil
}

func makeSet(gvks []schema.GroupVersionKind) map[schema.GroupVersionKind]struct{} {
Expand Down
Loading
Loading