add support for custom ClusterClaim configuration (#1004)
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1m14s
Post / coverage (push) Failing after 26m54s
Post / images (amd64) (push) Failing after 3m38s
Post / images (arm64) (push) Failing after 3m13s
Post / image manifest (push) Has been skipped
Post / trigger clusteradm e2e (push) Has been skipped
Close stale issues and PRs / stale (push) Successful in 37s

* vendor api

Signed-off-by: Omar Farag <omarfarag74@gmail.com>

* add support for maxCustomClusterClaim

Signed-off-by: Omar Farag <omarfarag74@gmail.com>

* support ReservedClusterClaimSuffixes

Signed-off-by: Omar Farag <omarfarag74@gmail.com>

* add and use klusterletinformer

Signed-off-by: Omar Farag <omarfarag74@gmail.com>

* fix tests

Signed-off-by: Omar Farag <omarfarag74@gmail.com>

* update for change in clusterclaimconfiguration api

Signed-off-by: Omar Farag <omarfarag74@gmail.com>

* requested changes, clean up

Signed-off-by: Omar Farag <omarfarag74@gmail.com>

* Use flag to pass the reservedClusterClaimSuffixes

Signed-off-by: zhujian <jiazhu@redhat.com>

* Add cluster claim tests

Signed-off-by: zhujian <jiazhu@redhat.com>

* use StringSliceVar to parse the reserved cluster claim suffixes flag

Signed-off-by: zhujian <jiazhu@redhat.com>

* fix rebase issues

Signed-off-by: zhujian <jiazhu@redhat.com>

* address code review comments

Signed-off-by: zhujian <jiazhu@redhat.com>

---------

Signed-off-by: Omar Farag <omarfarag74@gmail.com>
Signed-off-by: zhujian <jiazhu@redhat.com>
Co-authored-by: Omar Farag <omarfarag74@gmail.com>
This commit is contained in:
Jian Zhu
2025-05-27 12:09:41 +00:00
committed by GitHub
co-authored by Omar Farag
parent 3d7d770712
commit 4cbb12d5a2
13 changed files with 338 additions and 33 deletions
@@ -107,6 +107,12 @@ spec:
{{if gt .AgentKubeAPIBurst 0}}
- "--kube-api-burst={{ .AgentKubeAPIBurst }}"
{{end}}
{{if .MaxCustomClusterClaims}}
- "--max-custom-cluster-claims={{ .MaxCustomClusterClaims }}"
{{end}}
{{if .ReservedClusterClaimSuffixes}}
- "--reserved-cluster-claim-suffixes={{ .ReservedClusterClaimSuffixes }}"
{{end}}
{{if .AppliedManifestWorkEvictionGracePeriod}}
- "--appliedmanifestwork-eviction-grace-period={{ .AppliedManifestWorkEvictionGracePeriod }}"
{{end}}
@@ -94,6 +94,12 @@ spec:
{{if gt .RegistrationKubeAPIBurst 0}}
- "--kube-api-burst={{ .RegistrationKubeAPIBurst }}"
{{end}}
{{if .MaxCustomClusterClaims}}
- "--max-custom-cluster-claims={{ .MaxCustomClusterClaims }}"
{{end}}
{{if .ReservedClusterClaimSuffixes}}
- "--reserved-cluster-claim-suffixes={{ .ReservedClusterClaimSuffixes }}"
{{end}}
{{if eq .RegistrationDriver.AuthType "awsirsa"}}
- "--registration-auth={{ .RegistrationDriver.AuthType }}"
- "--hub-cluster-arn={{ .RegistrationDriver.AwsIrsa.HubClusterArn }}"
@@ -181,6 +181,8 @@ type klusterletConfig struct {
ExternalManagedKubeConfigAgentSecret string
InstallMode operatorapiv1.InstallMode
MaxCustomClusterClaims int
ReservedClusterClaimSuffixes string
// PriorityClassName is the name of the PriorityClass used by the deployed agents
PriorityClassName string
@@ -370,6 +372,14 @@ func (n *klusterletController) sync(ctx context.Context, controllerContext facto
AuthType: klusterlet.Spec.RegistrationConfiguration.RegistrationDriver.AuthType,
}
}
// include clusterClaimConfig info if it exists
if klusterlet.Spec.RegistrationConfiguration.ClusterClaimConfiguration != nil {
config.MaxCustomClusterClaims = int(klusterlet.Spec.RegistrationConfiguration.ClusterClaimConfiguration.MaxCustomClusterClaims)
config.ReservedClusterClaimSuffixes = strings.Join(
klusterlet.Spec.RegistrationConfiguration.ClusterClaimConfiguration.ReservedClusterClaimSuffixes, ",")
}
// construct cluster annotations string, the final format is "key1=value1,key2=value2"
var annotationsArray []string
for k, v := range commonhelpers.FilterClusterAnnotations(klusterlet.Spec.RegistrationConfiguration.ClusterAnnotations) {
@@ -377,7 +377,8 @@ func getDeployments(actions []clienttesting.Action, verb, suffix string) *appsv1
return nil
}
func assertKlusterletDeployment(t *testing.T, actions []clienttesting.Action, verb, serverURL, clusterName string) {
func assertKlusterletDeployment(t *testing.T, registrationAuthType string, actions []clienttesting.Action, verb, serverURL, clusterName string,
claimConfig *operatorapiv1.ClusterClaimConfiguration) {
deployment := getDeployments(actions, verb, "agent")
if deployment == nil {
t.Errorf("klusterlet deployment not found")
@@ -399,24 +400,39 @@ func assertKlusterletDeployment(t *testing.T, actions []clienttesting.Action, ve
"--bootstrap-kubeconfig=/spoke/bootstrap/kubeconfig",
}
expectedArgs = append(expectedArgs, "--agent-id=", "--workload-source-driver=kube", "--workload-source-config=/spoke/hub-kubeconfig/kubeconfig",
"--status-sync-interval=60s", "--kube-api-qps=20", "--kube-api-burst=60")
if serverURL != "" {
expectedArgs = append(expectedArgs, fmt.Sprintf("--spoke-external-server-urls=%s", serverURL))
}
expectedArgs = append(expectedArgs, "--agent-id=", "--workload-source-driver=kube", "--workload-source-config=/spoke/hub-kubeconfig/kubeconfig",
"--status-sync-interval=60s", "--kube-api-qps=20", "--kube-api-burst=60",
"--registration-auth=awsirsa",
"--hub-cluster-arn=arn:aws:eks:us-west-2:123456789012:cluster/hub-cluster1",
"--managed-cluster-arn=arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster1",
"--managed-cluster-role-suffix=7f8141296c75f2871e3d030f85c35692")
if claimConfig != nil {
if claimConfig.MaxCustomClusterClaims > 0 {
expectedArgs = append(expectedArgs, fmt.Sprintf("--max-custom-cluster-claims=%d", claimConfig.MaxCustomClusterClaims))
}
if len(claimConfig.ReservedClusterClaimSuffixes) > 0 {
expectedArgs = append(expectedArgs, fmt.Sprintf("--reserved-cluster-claim-suffixes=%s",
strings.Join(claimConfig.ReservedClusterClaimSuffixes, ",")))
}
}
if registrationAuthType == "awsirsa" {
expectedArgs = append(expectedArgs,
"--registration-auth=awsirsa",
"--hub-cluster-arn=arn:aws:eks:us-west-2:123456789012:cluster/hub-cluster1",
"--managed-cluster-arn=arn:aws:eks:us-west-2:123456789012:cluster/managed-cluster1",
"--managed-cluster-role-suffix=7f8141296c75f2871e3d030f85c35692")
}
if !equality.Semantic.DeepEqual(args, expectedArgs) {
t.Errorf("Expect args %v, but got %v", expectedArgs, args)
return
}
assert.True(t, isDotAwsMounted(volumeMounts))
assert.True(t, isDotAwsVolumePresent(volumes))
if registrationAuthType == "awsirsa" {
assert.True(t, isDotAwsMounted(volumeMounts))
assert.True(t, isDotAwsVolumePresent(volumes))
}
}
@@ -1075,7 +1091,7 @@ func TestAWSIrsaAuthInSingletonMode(t *testing.T) {
t.Errorf("Expected non error when sync, %v", err)
}
assertKlusterletDeployment(t, controller.kubeClient.Actions(), createVerb, "", "cluster1")
assertKlusterletDeployment(t, commonhelpers.AwsIrsaAuthType, controller.kubeClient.Actions(), createVerb, "", "cluster1", nil)
}
func TestAWSIrsaAuthInNonSingletonMode(t *testing.T) {
@@ -1413,6 +1429,40 @@ func TestRenderingResourceRequirements(t *testing.T) {
}
}
func TestClusterClaimConfigInSingletonMode(t *testing.T) {
klusterlet := newKlusterlet("klusterlet", "testns", "cluster1")
claimConfig := &operatorapiv1.ClusterClaimConfiguration{
MaxCustomClusterClaims: 2,
ReservedClusterClaimSuffixes: []string{"test1.io", "test2.io"},
}
if klusterlet.Spec.RegistrationConfiguration == nil {
klusterlet.Spec.RegistrationConfiguration = &operatorapiv1.RegistrationConfiguration{}
}
klusterlet.Spec.RegistrationConfiguration.ClusterClaimConfiguration = claimConfig
klusterlet.Spec.DeployOption.Mode = operatorapiv1.InstallModeSingleton
hubSecret := newSecret(helpers.HubKubeConfig, "testns")
hubSecret.Data["kubeconfig"] = []byte("dummykubeconfig")
hubSecret.Data["cluster-name"] = []byte("cluster1")
objects := []runtime.Object{
newNamespace("testns"),
newSecret(helpers.BootstrapHubKubeConfig, "testns"),
hubSecret,
}
syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet")
controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, false,
objects...)
err := controller.controller.sync(context.TODO(), syncContext)
if err != nil {
t.Errorf("Expected non error when sync, %v", err)
}
assertKlusterletDeployment(t, commonhelpers.CSRAuthType, controller.kubeClient.Actions(), createVerb,
"", "cluster1", claimConfig)
}
func newKubeConfig(host string) []byte {
configData, _ := runtime.Encode(clientcmdlatest.Codec, &clientcmdapi.Config{
Clusters: map[string]*clientcmdapi.Cluster{"test-cluster": {
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"sort"
"strings"
"github.com/openshift/library-go/pkg/operator/events"
"k8s.io/apimachinery/pkg/api/meta"
@@ -22,9 +23,10 @@ import (
const labelCustomizedOnly = "open-cluster-management.io/spoke-only"
type claimReconcile struct {
recorder events.Recorder
claimLister clusterv1alpha1listers.ClusterClaimLister
maxCustomClusterClaims int
recorder events.Recorder
claimLister clusterv1alpha1listers.ClusterClaimLister
maxCustomClusterClaims int
reservedClusterClaimSuffixes []string
}
func (r *claimReconcile) reconcile(ctx context.Context, cluster *clusterv1.ManagedCluster) (*clusterv1.ManagedCluster, reconcileState, error) {
@@ -55,13 +57,17 @@ func (r *claimReconcile) exposeClaims(ctx context.Context, cluster *clusterv1.Ma
return fmt.Errorf("unable to list cluster claims: %w", err)
}
reservedClaimNames := sets.NewString(clusterv1alpha1.ReservedClusterClaimNames[:]...)
// check if the cluster claim is one of the reserved claims or has a reserved suffix.
// if so, it will be treated as a reserved claim and will always be exposed.
reservedClaimNames := sets.New(clusterv1alpha1.ReservedClusterClaimNames[:]...)
reservedClaimSuffixes := sets.New(r.reservedClusterClaimSuffixes...)
for _, clusterClaim := range clusterClaims {
managedClusterClaim := clusterv1.ManagedClusterClaim{
Name: clusterClaim.Name,
Value: clusterClaim.Spec.Value,
}
if reservedClaimNames.Has(clusterClaim.Name) {
if matchReservedClaims(reservedClaimNames, reservedClaimSuffixes, managedClusterClaim) {
reservedClaims = append(reservedClaims, managedClusterClaim)
continue
}
@@ -90,3 +96,16 @@ func (r *claimReconcile) exposeClaims(ctx context.Context, cluster *clusterv1.Ma
cluster.Status.ClusterClaims = claims
return nil
}
func matchReservedClaims(reservedClaims, reservedSuffixes sets.Set[string], claim clusterv1.ManagedClusterClaim) bool {
if reservedClaims.Has(claim.Name) {
return true
}
for suffix := range reservedSuffixes {
if strings.HasSuffix(claim.Name, suffix) {
return true
}
}
return false
}
@@ -29,8 +29,11 @@ import (
testinghelpers "open-cluster-management.io/ocm/pkg/registration/helpers/testing"
)
func TestSync(t *testing.T) {
func init() {
utilruntime.Must(features.SpokeMutableFeatureGate.Add(ocmfeature.DefaultSpokeRegistrationFeatureGates))
}
func TestSync(t *testing.T) {
cases := []struct {
name string
cluster runtime.Object
@@ -125,6 +128,7 @@ func TestSync(t *testing.T) {
clusterInformerFactory.Cluster().V1alpha1().ClusterClaims(),
kubeInformerFactory.Core().V1().Nodes(),
20,
[]string{},
eventstesting.NewTestingEventRecorder(t),
hubEventRecorder,
)
@@ -139,12 +143,13 @@ func TestSync(t *testing.T) {
func TestExposeClaims(t *testing.T) {
cases := []struct {
name string
cluster *clusterv1.ManagedCluster
claims []*clusterv1alpha1.ClusterClaim
maxCustomClusterClaims int
validateActions func(t *testing.T, actions []clienttesting.Action)
expectedErr string
name string
cluster *clusterv1.ManagedCluster
claims []*clusterv1alpha1.ClusterClaim
maxCustomClusterClaims int
reservedClusterClaimSuffixes []string
validateActions func(t *testing.T, actions []clienttesting.Action)
expectedErr string
}{
{
name: "sync claims into status of the managed cluster",
@@ -207,6 +212,14 @@ func TestExposeClaims(t *testing.T) {
Value: "cluster1",
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "id-test.k8s.io",
},
Spec: clusterv1alpha1.ClusterClaimSpec{
Value: "cluster1",
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "c",
@@ -245,6 +258,85 @@ func TestExposeClaims(t *testing.T) {
}
},
},
{
name: "keep custom reserved cluster claims",
cluster: testinghelpers.NewJoinedManagedCluster(),
claims: []*clusterv1alpha1.ClusterClaim{
{
ObjectMeta: metav1.ObjectMeta{
Name: "a",
},
Spec: clusterv1alpha1.ClusterClaimSpec{
Value: "b",
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "e",
},
Spec: clusterv1alpha1.ClusterClaimSpec{
Value: "f",
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "id.k8s.io",
},
Spec: clusterv1alpha1.ClusterClaimSpec{
Value: "cluster1",
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "c",
},
Spec: clusterv1alpha1.ClusterClaimSpec{
Value: "d",
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "test.reserved.io",
},
Spec: clusterv1alpha1.ClusterClaimSpec{
Value: "test",
},
},
},
maxCustomClusterClaims: 2,
reservedClusterClaimSuffixes: []string{"reserved.io"},
validateActions: func(t *testing.T, actions []clienttesting.Action) {
testingcommon.AssertActions(t, actions, "patch")
patch := actions[0].(clienttesting.PatchAction).GetPatch()
cluster := &clusterv1.ManagedCluster{}
err := json.Unmarshal(patch, cluster)
if err != nil {
t.Fatal(err)
}
expected := []clusterv1.ManagedClusterClaim{
{
Name: "id.k8s.io",
Value: "cluster1",
},
{
Name: "test.reserved.io",
Value: "test",
},
{
Name: "a",
Value: "b",
},
{
Name: "c",
Value: "d",
},
}
actual := cluster.Status.ClusterClaims
if !reflect.DeepEqual(actual, expected) {
t.Errorf("expected cluster claim %v but got: %v", expected, actual)
}
},
},
{
name: "remove claims from managed cluster",
cluster: newManagedCluster([]clusterv1.ManagedClusterClaim{
@@ -356,6 +448,7 @@ func TestExposeClaims(t *testing.T) {
clusterInformerFactory.Cluster().V1alpha1().ClusterClaims(),
kubeInformerFactory.Core().V1().Nodes(),
c.maxCustomClusterClaims,
c.reservedClusterClaimSuffixes,
eventstesting.NewTestingEventRecorder(t),
hubEventRecorder,
)
@@ -96,6 +96,7 @@ func TestSyncManagedCluster(t *testing.T) {
clusterInformerFactory.Cluster().V1alpha1().ClusterClaims(),
kubeInformerFactory.Core().V1().Nodes(),
20,
[]string{},
eventstesting.NewTestingEventRecorder(t),
hubEventRecorder,
)
@@ -330,6 +330,7 @@ func TestHealthCheck(t *testing.T) {
clusterInformerFactory.Cluster().V1alpha1().ClusterClaims(),
kubeInformerFactory.Core().V1().Nodes(),
20,
[]string{},
eventstesting.NewTestingEventRecorder(t),
hubEventRecorder,
)
@@ -54,6 +54,7 @@ func NewManagedClusterStatusController(
claimInformer clusterv1alpha1informer.ClusterClaimInformer,
nodeInformer corev1informers.NodeInformer,
maxCustomClusterClaims int,
reservedClusterClaimSuffixes []string,
resyncInterval time.Duration,
recorder events.Recorder,
hubEventRecorder kevents.EventRecorder) factory.Controller {
@@ -65,6 +66,7 @@ func NewManagedClusterStatusController(
claimInformer,
nodeInformer,
maxCustomClusterClaims,
reservedClusterClaimSuffixes,
recorder,
hubEventRecorder,
)
@@ -84,6 +86,7 @@ func newManagedClusterStatusController(
claimInformer clusterv1alpha1informer.ClusterClaimInformer,
nodeInformer corev1informers.NodeInformer,
maxCustomClusterClaims int,
reservedClusterClaimSuffixes []string,
recorder events.Recorder,
hubEventRecorder kevents.EventRecorder) *managedClusterStatusController {
return &managedClusterStatusController{
@@ -94,7 +97,8 @@ func newManagedClusterStatusController(
reconcilers: []statusReconcile{
&joiningReconcile{recorder: recorder},
&resoureReconcile{managedClusterDiscoveryClient: managedClusterDiscoveryClient, nodeLister: nodeInformer.Lister()},
&claimReconcile{claimLister: claimInformer.Lister(), recorder: recorder, maxCustomClusterClaims: maxCustomClusterClaims},
&claimReconcile{claimLister: claimInformer.Lister(), recorder: recorder,
maxCustomClusterClaims: maxCustomClusterClaims, reservedClusterClaimSuffixes: reservedClusterClaimSuffixes},
},
hubClusterLister: hubClusterInformer.Lister(),
hubEventRecorder: hubEventRecorder,
+8 -5
View File
@@ -30,11 +30,12 @@ type SpokeAgentOptions struct {
// See more details in: https://github.com/open-cluster-management-io/ocm/pull/443#discussion_r1610868646
HubConnectionTimeoutSeconds int32
HubKubeconfigSecret string
SpokeExternalServerURLs []string
ClusterHealthCheckPeriod time.Duration
MaxCustomClusterClaims int
ClusterAnnotations map[string]string
HubKubeconfigSecret string
SpokeExternalServerURLs []string
ClusterHealthCheckPeriod time.Duration
MaxCustomClusterClaims int
ReservedClusterClaimSuffixes []string
ClusterAnnotations map[string]string
RegisterDriverOption *registerfactory.Options
}
@@ -71,6 +72,8 @@ func (o *SpokeAgentOptions) AddFlags(fs *pflag.FlagSet) {
"The period to check managed cluster kube-apiserver health")
fs.IntVar(&o.MaxCustomClusterClaims, "max-custom-cluster-claims", o.MaxCustomClusterClaims,
"The max number of custom cluster claims to expose.")
fs.StringSliceVar(&o.ReservedClusterClaimSuffixes, "reserved-cluster-claim-suffixes", o.ReservedClusterClaimSuffixes,
"A list of suffixes for reserved cluster claims.")
fs.StringToStringVar(&o.ClusterAnnotations, "cluster-annotations", o.ClusterAnnotations, `the annotations with the reserve
prefix "agent.open-cluster-management.io" set on ManagedCluster when creating only, other actors can update it afterwards.`)
+1
View File
@@ -358,6 +358,7 @@ func (o *SpokeAgentConfig) RunSpokeAgentWithSpokeInformers(ctx context.Context,
spokeClusterInformerFactory.Cluster().V1alpha1().ClusterClaims(),
spokeKubeInformerFactory.Core().V1().Nodes(),
o.registrationOption.MaxCustomClusterClaims,
o.registrationOption.ReservedClusterClaimSuffixes,
o.registrationOption.ClusterHealthCheckPeriod,
recorder,
hubEventRecorder,
@@ -789,6 +789,74 @@ var _ = ginkgo.Describe("Klusterlet", func() {
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
})
ginkgo.It("Deployment should be updated when klusterlet claim configure is changed", func() {
_, err := operatorClient.OperatorV1().Klusterlets().Create(context.Background(), klusterlet, metav1.CreateOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Eventually(func() bool {
if _, err := kubeClient.AppsV1().Deployments(klusterletNamespace).Get(context.Background(), workDeploymentName, metav1.GetOptions{}); err != nil {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
// Check if generations are correct
gomega.Eventually(func() bool {
actual, err := operatorClient.OperatorV1().Klusterlets().Get(context.Background(), klusterlet.Name, metav1.GetOptions{})
if err != nil {
return false
}
if actual.Generation != actual.Status.ObservedGeneration {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
gomega.Eventually(func() error {
klusterlet, err = operatorClient.OperatorV1().Klusterlets().Get(context.Background(), klusterlet.Name, metav1.GetOptions{})
if err != nil {
return err
}
klusterlet.Spec.RegistrationConfiguration = &operatorapiv1.RegistrationConfiguration{
ClusterClaimConfiguration: &operatorapiv1.ClusterClaimConfiguration{
MaxCustomClusterClaims: 2,
ReservedClusterClaimSuffixes: []string{"reserved1.io", "reserved2.io"},
},
}
_, err = operatorClient.OperatorV1().Klusterlets().Update(context.Background(), klusterlet, metav1.UpdateOptions{})
return err
}, eventuallyTimeout, eventuallyInterval).Should(gomega.Succeed())
gomega.Eventually(func() bool {
actual, err := kubeClient.AppsV1().Deployments(klusterletNamespace).Get(context.Background(), registrationDeploymentName, metav1.GetOptions{})
if err != nil {
return false
}
gomega.Expect(len(actual.Spec.Template.Spec.Containers)).Should(gomega.Equal(1))
if len(actual.Spec.Template.Spec.Containers[0].Args) != 9 {
return false
}
return actual.Spec.Template.Spec.Containers[0].Args[7] == "--max-custom-cluster-claims=2" &&
actual.Spec.Template.Spec.Containers[0].Args[8] == "--reserved-cluster-claim-suffixes=reserved1.io,reserved2.io"
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
// Check if generations are correct
gomega.Eventually(func() bool {
actual, err := operatorClient.OperatorV1().Klusterlets().Get(context.Background(), klusterlet.Name, metav1.GetOptions{})
if err != nil {
return false
}
if actual.Generation != actual.Status.ObservedGeneration {
return false
}
return true
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
})
})
ginkgo.Context("klusterlet statuses", func() {
@@ -27,6 +27,7 @@ var _ = ginkgo.Describe("Cluster Claim", func() {
var managedClusterName, hubKubeconfigSecret, hubKubeconfigDir string
var claims []*clusterv1alpha1.ClusterClaim
var maxCustomClusterClaims int
var reservedClusterClaimSuffixes []string
var err error
var cancel context.CancelFunc
@@ -52,11 +53,12 @@ var _ = ginkgo.Describe("Cluster Claim", func() {
// run registration agent
agentOptions := &spoke.SpokeAgentOptions{
BootstrapKubeconfig: bootstrapKubeConfigFile,
HubKubeconfigSecret: hubKubeconfigSecret,
ClusterHealthCheckPeriod: 1 * time.Minute,
MaxCustomClusterClaims: maxCustomClusterClaims,
RegisterDriverOption: registerfactory.NewOptions(),
BootstrapKubeconfig: bootstrapKubeConfigFile,
HubKubeconfigSecret: hubKubeconfigSecret,
ClusterHealthCheckPeriod: 1 * time.Minute,
MaxCustomClusterClaims: maxCustomClusterClaims,
ReservedClusterClaimSuffixes: reservedClusterClaimSuffixes,
RegisterDriverOption: registerfactory.NewOptions(),
}
commOptions := commonoptions.NewAgentOptions()
commOptions.HubKubeconfigDir = hubKubeconfigDir
@@ -271,4 +273,45 @@ var _ = ginkgo.Describe("Cluster Claim", func() {
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
})
})
ginkgo.Context("Keep custom reserved claims", func() {
ginkgo.BeforeEach(func() {
maxCustomClusterClaims = 5
reservedClusterClaimSuffixes = []string{"reserved.io"}
claims = []*clusterv1alpha1.ClusterClaim{
{
ObjectMeta: metav1.ObjectMeta{
Name: "claim.reserved.io",
},
Spec: clusterv1alpha1.ClusterClaimSpec{
Value: "value-test",
},
},
}
for i := 0; i < 10; i++ {
claims = append(claims, &clusterv1alpha1.ClusterClaim{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("claim-%d", i),
},
Spec: clusterv1alpha1.ClusterClaimSpec{
Value: fmt.Sprintf("value-%d", i),
},
})
}
})
ginkgo.It("should sync custom suffix claims to status of ManagedCluster", func() {
assertSuccessBootstrap()
ginkgo.By("Sync claims")
gomega.Eventually(func() bool {
spokeCluster, err := util.GetManagedCluster(clusterClient, managedClusterName)
if err != nil {
return false
}
return len(spokeCluster.Status.ClusterClaims) == maxCustomClusterClaims+1
}, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue())
})
})
})