Skip to content

Commit

Permalink
Add skippedPropagatingAPIs option
Browse files Browse the repository at this point in the history
Signed-off-by: pigletfly <[email protected]>
  • Loading branch information
pigletfly committed Jul 8, 2021
1 parent 6db6baf commit d4bbde2
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 18 deletions.
17 changes: 10 additions & 7 deletions cmd/controller-manager/app/controllermanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,20 @@ func setupControllers(mgr controllerruntime.Manager, opts *options.Options, stop
resetConfig := mgr.GetConfig()
dynamicClientSet := dynamic.NewForConfigOrDie(resetConfig)
discoverClientSet := discovery.NewDiscoveryClientForConfigOrDie(resetConfig)

objectWatcher := objectwatcher.NewObjectWatcher(mgr.GetClient(), mgr.GetRESTMapper(), util.NewClusterDynamicClientSet)
overrideManager := overridemanager.New(mgr.GetClient())

skippedResourceConfig := util.NewSkippedResourceConfig()
// TODO(pigletfly): add SkippedPropagatingAPIs validation
skippedResourceConfig.Parse(opts.SkippedPropagatingAPIs)
resourceDetector := &detector.ResourceDetector{
DiscoveryClientSet: discoverClientSet,
Client: mgr.GetClient(),
InformerManager: informermanager.NewSingleClusterInformerManager(dynamicClientSet, 0),
RESTMapper: mgr.GetRESTMapper(),
DynamicClient: dynamicClientSet,
DiscoveryClientSet: discoverClientSet,
Client: mgr.GetClient(),
InformerManager: informermanager.NewSingleClusterInformerManager(dynamicClientSet, 0),
RESTMapper: mgr.GetRESTMapper(),
DynamicClient: dynamicClientSet,
SkippedResourceConfig: skippedResourceConfig,
}

resourceDetector.EventHandler = informermanager.NewFilteringHandlerOnAllEvents(resourceDetector.EventFilter, resourceDetector.OnAdd, resourceDetector.OnUpdate, resourceDetector.OnDelete)
resourceDetector.Processor = util.NewAsyncWorker("resource detector", time.Microsecond, detector.ClusterWideKeyFunc, resourceDetector.Reconcile)
if err := mgr.Add(resourceDetector); err != nil {
Expand Down
6 changes: 6 additions & 0 deletions cmd/controller-manager/app/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ type Options struct {
ClusterMonitorGracePeriod metav1.Duration
// When cluster is just created, e.g. agent bootstrap or cluster join, we give a longer grace period.
ClusterStartupGracePeriod metav1.Duration
// SkippedPropagatingAPIs indicates comma separated resources that should be skipped for propagating.
SkippedPropagatingAPIs string
}

// NewOptions builds an empty options.
Expand Down Expand Up @@ -103,4 +105,8 @@ func (o *Options) AddFlags(flags *pflag.FlagSet) {
"Specifies the grace period of allowing a running cluster to be unresponsive before marking it unhealthy.")
flags.DurationVar(&o.ClusterStartupGracePeriod.Duration, "cluster-startup-grace-period", 60*time.Second,
"Specifies the grace period of allowing a cluster to be unresponsive during startup before marking it unhealthy.")
flags.StringVar(&o.SkippedPropagatingAPIs, "skipped-propagating-apis", "", "Semicolon separated resources that should be skipped from propagating in addition to the default skip list(cluster.karmada.io;policy.karmada.io;work.karmada.io). Supported formats are:\n"+
"<group> for skip resources with a specific API group(e.g. networking.k8s.io),\n"+
"<group>/<version> for skip resources with a specific API version(e.g. networking.k8s.io/v1beta1),\n"+
"<group>/<version>/<kind>,<kind> for skip one or more specific resource(e.g. networking.k8s.io/v1beta1/Ingress,IngressClass) where the kinds are case-insensitive.")
}
1 change: 1 addition & 0 deletions pkg/controllers/namespace/namespace_sync_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func (c *Controller) namespaceShouldBeSynced(namespace string) bool {
strings.HasPrefix(namespace, karmadaExecutionSpacePrefix) || strings.HasPrefix(namespace, kubeSystemNamespacePrefix) {
return false
}

return true
}

Expand Down
143 changes: 143 additions & 0 deletions pkg/util/apigroup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package util

import (
"strings"

"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog/v2"

clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1"
)

// SkippedResourceConfig represents the configuration that identifies the API resources should be skipped from propagating.
type SkippedResourceConfig struct {
// Groups holds a collection of API group, all resources under this group will be skipped.
Groups map[string]struct{}
// GroupVersions holds a collection of API GroupVersion, all resource under this GroupVersion will be skipped.
GroupVersions map[schema.GroupVersion]struct{}
// GroupVersionKinds holds a collection of resource that should be skipped.
GroupVersionKinds map[schema.GroupVersionKind]struct{}
}

// NewSkippedResourceConfig to create SkippedResourceConfig
func NewSkippedResourceConfig() *SkippedResourceConfig {
r := &SkippedResourceConfig{
Groups: map[string]struct{}{},
GroupVersions: map[schema.GroupVersion]struct{}{},
GroupVersionKinds: map[schema.GroupVersionKind]struct{}{},
}
// disable karmada group by default
r.DisableGroup(clusterv1alpha1.GroupVersion.Group)
r.DisableGroup(policyv1alpha1.GroupVersion.Group)
r.DisableGroup(workv1alpha1.GroupVersion.Group)
return r
}

// Parse to parse tokens to SkippedResourceConfig
func (r *SkippedResourceConfig) Parse(c string) {
// v1/Node,Pod;networking.k8s.io/v1beta1/Ingress,IngressClass
// group networking.k8s.io
// group version networking.k8s.io/v1
// group version kind networking.k8s.io/v1/Ingress
// corev1 has no group
if c == "" {
return
}

tokens := strings.Split(c, ";")
for _, token := range tokens {
r.parseSingle(token)
}
}

func (r *SkippedResourceConfig) parseSingle(token string) {
switch strings.Count(token, "/") {
case 0:
// Group
r.Groups[token] = struct{}{}
case 1:
if strings.HasPrefix(token, "v1") {
// core v1
kinds := []string{}
for _, k := range strings.Split(token, ",") {
if strings.Contains(k, "/") {
s := strings.Split(k, "/")
kinds = append(kinds, s[1])
} else {
kinds = append(kinds, k)
}
}
for _, k := range kinds {
gvk := schema.GroupVersionKind{
Version: "v1",
Kind: k,
}
r.GroupVersionKinds[gvk] = struct{}{}
}
} else {
// GroupVersion
i := strings.Index(token, "/")
gv := schema.GroupVersion{
Group: token[:i],
Version: token[i+1:],
}
r.GroupVersions[gv] = struct{}{}
}
case 2:
// GroupVersionKind
g := ""
v := ""
kinds := []string{}
for _, k := range strings.Split(token, ",") {
if strings.Contains(k, "/") {
s := strings.Split(k, "/")
g = s[0]
v = s[1]
kinds = append(kinds, s[2])
} else {
kinds = append(kinds, k)
}
}
for _, k := range kinds {
gvk := schema.GroupVersionKind{
Group: g,
Version: v,
Kind: k,
}
r.GroupVersionKinds[gvk] = struct{}{}
}
default:
klog.Error("Unsupported SkippedPropagatingAPIs: ", token)
}
}

// GroupVersionDisabled returns whether GroupVersion is disabled.
func (r *SkippedResourceConfig) GroupVersionDisabled(gv schema.GroupVersion) bool {
if _, ok := r.GroupVersions[gv]; ok {
return true
}
return false
}

// GroupVersionKindDisabled returns whether GroupVersionKind is disabled.
func (r *SkippedResourceConfig) GroupVersionKindDisabled(gvk schema.GroupVersionKind) bool {
if _, ok := r.GroupVersionKinds[gvk]; ok {
return true
}
return false
}

// GroupDisabled returns whether Group is disabled.
func (r *SkippedResourceConfig) GroupDisabled(g string) bool {
if _, ok := r.Groups[g]; ok {
return true
}
return false
}

// DisableGroup to disable group.
func (r *SkippedResourceConfig) DisableGroup(g string) {
r.Groups[g] = struct{}{}
}
193 changes: 193 additions & 0 deletions pkg/util/apigroup_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package util

import (
"testing"

"k8s.io/apimachinery/pkg/runtime/schema"
)

func TestSkippedResourceConfigGVKParse(t *testing.T) {
tests := []struct {
input string
out []schema.GroupVersionKind
}{
{input: "v1/Node,Pod;networking.k8s.io/v1beta1/Ingress,IngressClass", out: []schema.GroupVersionKind{
{
Group: "",
Version: "v1",
Kind: "Node",
},
{
Group: "",
Version: "v1",
Kind: "Pod",
},
{
Group: "networking.k8s.io",
Version: "v1beta1",
Kind: "Ingress",
},
{
Group: "networking.k8s.io",
Version: "v1beta1",
Kind: "IngressClass",
},
}},
}
for _, test := range tests {
r := NewSkippedResourceConfig()
r.Parse(test.input)
for i, o := range test.out {
ok := r.GroupVersionKindDisabled(o)
if !ok {
t.Errorf("%d: unexpected error: %v", i, o)
}
}
}
}
func TestResourceConfigGVParse(t *testing.T) {
tests := []struct {
input string
out []schema.GroupVersion
}{
{input: "networking.k8s.io/v1;test/v1beta1", out: []schema.GroupVersion{
{
Group: "networking.k8s.io",
Version: "v1",
},
{
Group: "networking.k8s.io",
Version: "v1",
},
{
Group: "test",
Version: "v1beta1",
},
{
Group: "test",
Version: "v1beta1",
},
}},
}
for _, test := range tests {
r := NewSkippedResourceConfig()
r.Parse(test.input)
for i, o := range test.out {
ok := r.GroupVersionDisabled(o)
if !ok {
t.Errorf("%d: unexpected error: %v", i, o)
}
}
}
}

func TestSkippedResourceConfigGroupParse(t *testing.T) {
tests := []struct {
input string
out []string
}{
{input: "networking.k8s.io;test", out: []string{
"networking.k8s.io", "test",
}},
}
for _, test := range tests {
r := NewSkippedResourceConfig()
r.Parse(test.input)
for i, o := range test.out {
ok := r.GroupDisabled(o)
if !ok {
t.Errorf("%d: unexpected error: %v", i, o)
}
}
}
}

func TestSkippedResourceConfigMixedParse(t *testing.T) {
tests := []struct {
input string
out SkippedResourceConfig
}{
{input: "v1/Node,Pod;networking.k8s.io/v1beta1/Ingress,IngressClass;networking.k8s.io;test.com/v1", out: SkippedResourceConfig{
Groups: map[string]struct{}{
"networking.k8s.io": {},
},
GroupVersions: map[schema.GroupVersion]struct{}{
{
Group: "test.com",
Version: "v1",
}: {},
},
GroupVersionKinds: map[schema.GroupVersionKind]struct{}{
{
Group: "",
Version: "v1",
Kind: "Node",
}: {},
{
Group: "",
Version: "v1",
Kind: "Pod",
}: {},
{
Group: "networking.k8s.io",
Version: "v1beta1",
Kind: "Ingress",
}: {},
{
Group: "networking.k8s.io",
Version: "v1beta1",
Kind: "IngressClass",
}: {},
},
}},
}
for i, test := range tests {
r := NewSkippedResourceConfig()
r.Parse(test.input)
for g := range r.Groups {
ok := r.GroupDisabled(g)
if !ok {
t.Errorf("%d: unexpected error: %v", i, g)
}
}

for gv := range r.GroupVersions {
ok := r.GroupVersionDisabled(gv)
if !ok {
t.Errorf("%d: unexpected error: %v", i, gv)
}
}

for gvk := range r.GroupVersionKinds {
ok := r.GroupVersionKindDisabled(gvk)
if !ok {
t.Errorf("%d: unexpected error: %v", i, gvk)
}
}
}
}

func TestDefaultSkippedResourceConfigGroupParse(t *testing.T) {
tests := []struct {
input string
out []string
}{
{input: "", out: []string{
"cluster.karmada.io", "policy.karmada.io", "work.karmada.io",
}},
}
for _, test := range tests {
r := NewSkippedResourceConfig()
r.Parse(test.input)
for i, o := range test.out {
ok := r.GroupDisabled(o)
if !ok {
t.Errorf("%d: unexpected error: %v", i, o)
}
}
ok := r.GroupDisabled("")
if ok {
t.Error("unexpected error: v1")
}
}
}
Loading

0 comments on commit d4bbde2

Please sign in to comment.