mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-02-14 18:09:57 +00:00
sync labels from klusterlet to all agent resources (#475)
Signed-off-by: Zhiwei Yin <zyin@redhat.com>
This commit is contained in:
@@ -52,6 +52,9 @@ const (
|
||||
|
||||
// DefaultAddonNamespace is the default namespace for agent addon
|
||||
DefaultAddonNamespace = "open-cluster-management-agent-addon"
|
||||
|
||||
// AgentLabelKey is used to filter resources in informers
|
||||
AgentLabelKey = "createdByKlusterlet"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -666,7 +669,7 @@ func AgentPriorityClassName(klusterlet *operatorapiv1.Klusterlet, kubeVersion *v
|
||||
// https://github.com/openshift/library-go/blob/d9cdfbd844ea08465b938c46a16bed2ea23207e4/pkg/operator/resource/resourceapply/core.go#L357,
|
||||
// add an addition targetClient parameter to support sync secret to another cluster.
|
||||
func SyncSecret(ctx context.Context, client, targetClient coreclientv1.SecretsGetter, recorder events.Recorder,
|
||||
sourceNamespace, sourceName, targetNamespace, targetName string, ownerRefs []metav1.OwnerReference) (*corev1.Secret, bool, error) {
|
||||
sourceNamespace, sourceName, targetNamespace, targetName string, ownerRefs []metav1.OwnerReference, labels map[string]string) (*corev1.Secret, bool, error) {
|
||||
source, err := client.Secrets(sourceNamespace).Get(ctx, sourceName, metav1.GetOptions{})
|
||||
switch {
|
||||
case errors.IsNotFound(err):
|
||||
@@ -707,6 +710,7 @@ func SyncSecret(ctx context.Context, client, targetClient coreclientv1.SecretsGe
|
||||
source.Name = targetName
|
||||
source.ResourceVersion = ""
|
||||
source.OwnerReferences = ownerRefs
|
||||
source.Labels = labels
|
||||
return resourceapply.ApplySecret(ctx, targetClient, recorder, source)
|
||||
}
|
||||
}
|
||||
@@ -821,3 +825,24 @@ func GetOperatorNamespace() string {
|
||||
}
|
||||
return operatorNamespace
|
||||
}
|
||||
|
||||
func GetKlusterletAgentLabels(klusterlet *operatorapiv1.Klusterlet) map[string]string {
|
||||
labels := klusterlet.GetLabels()
|
||||
if labels == nil {
|
||||
labels = map[string]string{}
|
||||
}
|
||||
|
||||
// This label key is used to filter resources in deployment informer
|
||||
labels[AgentLabelKey] = klusterlet.GetName()
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
func MapCompare(required, existing map[string]string) bool {
|
||||
for k, v := range required {
|
||||
if existing[k] != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1477,7 +1477,8 @@ func TestSyncSecret(t *testing.T) {
|
||||
clientTarget := fakekube.NewSimpleClientset()
|
||||
secret, changed, err := SyncSecret(
|
||||
context.TODO(), client.CoreV1(), clientTarget.CoreV1(),
|
||||
events.NewInMemoryRecorder("test"), tc.sourceNamespace, tc.sourceName, tc.targetNamespace, tc.targetName, tc.ownerRefs)
|
||||
events.NewInMemoryRecorder("test"), tc.sourceNamespace, tc.sourceName,
|
||||
tc.targetNamespace, tc.targetName, tc.ownerRefs, nil)
|
||||
|
||||
if (err == nil && len(tc.expectedErr) != 0) || (err != nil && err.Error() != tc.expectedErr) {
|
||||
t.Errorf("%s: expected error %v, got %v", tc.name, tc.expectedErr, err)
|
||||
|
||||
@@ -104,12 +104,12 @@ func SATokenCreater(ctx context.Context, saName, saNamespace string, saClient ku
|
||||
|
||||
func SyncKubeConfigSecret(ctx context.Context, secretName, secretNamespace, kubeconfigPath string,
|
||||
templateKubeconfig *rest.Config, secretClient coreclientv1.SecretsGetter,
|
||||
tokenGetter TokenGetterFunc, recorder events.Recorder) error {
|
||||
tokenGetter TokenGetterFunc, recorder events.Recorder, labels map[string]string) error {
|
||||
secret, err := secretClient.Secrets(secretNamespace).Get(ctx, secretName, metav1.GetOptions{})
|
||||
switch {
|
||||
case errors.IsNotFound(err):
|
||||
return applyKubeconfigSecret(ctx, templateKubeconfig, secretName, secretNamespace,
|
||||
kubeconfigPath, secretClient, tokenGetter, recorder)
|
||||
kubeconfigPath, secretClient, tokenGetter, recorder, labels)
|
||||
case err != nil:
|
||||
return err
|
||||
}
|
||||
@@ -118,7 +118,8 @@ func SyncKubeConfigSecret(ctx context.Context, secretName, secretNamespace, kube
|
||||
return nil
|
||||
}
|
||||
|
||||
return applyKubeconfigSecret(ctx, templateKubeconfig, secretName, secretNamespace, kubeconfigPath, secretClient, tokenGetter, recorder)
|
||||
return applyKubeconfigSecret(ctx, templateKubeconfig, secretName, secretNamespace, kubeconfigPath,
|
||||
secretClient, tokenGetter, recorder, labels)
|
||||
}
|
||||
|
||||
func tokenValid(secret *corev1.Secret, tokenGetter TokenGetterFunc) bool {
|
||||
@@ -200,7 +201,7 @@ func clusterInfoNotChanged(secret *corev1.Secret, templateKubeconfig *rest.Confi
|
||||
// applyKubeconfigSecret would render saToken to a secret.
|
||||
func applyKubeconfigSecret(ctx context.Context, templateKubeconfig *rest.Config, secretName, secretNamespace,
|
||||
kubeconfigPath string, secretClient coreclientv1.SecretsGetter, tokenGetter TokenGetterFunc,
|
||||
recorder events.Recorder) error {
|
||||
recorder events.Recorder, labels map[string]string) error {
|
||||
|
||||
token, expiration, additionalData, err := tokenGetter()
|
||||
if err != nil {
|
||||
@@ -239,6 +240,7 @@ func applyKubeconfigSecret(ctx context.Context, templateKubeconfig *rest.Config,
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: secretNamespace,
|
||||
Name: secretName,
|
||||
Labels: labels,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"kubeconfig": kubeconfigContent,
|
||||
|
||||
@@ -270,7 +270,7 @@ func TestApplyKubeconfigSecret(t *testing.T) {
|
||||
err := SyncKubeConfigSecret(
|
||||
context.TODO(), secretName, secretNamespace,
|
||||
"/tmp/kubeconfig", tkc, client.CoreV1(), tokenGetter,
|
||||
eventstesting.NewTestingEventRecorder(t))
|
||||
eventstesting.NewTestingEventRecorder(t), nil)
|
||||
if err != nil && !tt.wantErr {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -347,7 +347,7 @@ func ensureSAKubeconfigs(ctx context.Context, clusterManagerName, clusterManager
|
||||
TLSClientConfig: rest.TLSClientConfig{
|
||||
CAData: hubKubeConfig.CAData,
|
||||
},
|
||||
}, managementClient.CoreV1(), tokenGetter, recorder)
|
||||
}, managementClient.CoreV1(), tokenGetter, recorder, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ func (c *secretReconcile) reconcile(ctx context.Context, cm *operatorapiv1.Clust
|
||||
config.ClusterManagerNamespace,
|
||||
secretName,
|
||||
[]metav1.OwnerReference{},
|
||||
nil,
|
||||
); err != nil {
|
||||
syncedErrs = append(syncedErrs, fmt.Errorf("failed to sync secret %s: %v", secretName, err))
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ func (c *addonPullImageSecretController) sync(ctx context.Context, controllerCon
|
||||
namespace,
|
||||
helpers.ImagePullSecret,
|
||||
[]metav1.OwnerReference{},
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/openshift/library-go/pkg/controller/factory"
|
||||
"github.com/openshift/library-go/pkg/operator/events"
|
||||
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
|
||||
"github.com/openshift/library-go/pkg/operator/resource/resourcemerge"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -166,6 +167,9 @@ type klusterletConfig struct {
|
||||
|
||||
// DisableAddonNamespace is the flag to disable the creationg of default addon namespace.
|
||||
DisableAddonNamespace bool
|
||||
|
||||
// Labels of the agents are synced from klusterlet CR.
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
func (n *klusterletController) sync(ctx context.Context, controllerContext factory.SyncContext) error {
|
||||
@@ -221,6 +225,7 @@ func (n *klusterletController) sync(ctx context.Context, controllerContext facto
|
||||
ResourceRequirementResourceType: helpers.ResourceType(klusterlet),
|
||||
ResourceRequirements: resourceRequirements,
|
||||
DisableAddonNamespace: n.disableAddonNamespace,
|
||||
Labels: helpers.GetKlusterletAgentLabels(klusterlet),
|
||||
}
|
||||
|
||||
managedClusterClients, err := n.managedClusterClientsBuilder.
|
||||
@@ -418,6 +423,7 @@ func syncPullSecret(ctx context.Context, sourceClient, targetClient kubernetes.I
|
||||
namespace,
|
||||
helpers.ImagePullSecret,
|
||||
[]metav1.OwnerReference{},
|
||||
helpers.GetKlusterletAgentLabels(klusterlet),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@@ -436,6 +442,8 @@ func ensureNamespace(
|
||||
kubeClient kubernetes.Interface,
|
||||
klusterlet *operatorapiv1.Klusterlet,
|
||||
namespace string, labels map[string]string, recorder events.Recorder) error {
|
||||
modified := resourcemerge.BoolPtr(false)
|
||||
resourcemerge.MergeMap(modified, &labels, helpers.GetKlusterletAgentLabels(klusterlet))
|
||||
_, _, err := resourceapply.ApplyNamespace(ctx, kubeClient.CoreV1(), recorder, &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespace,
|
||||
|
||||
@@ -463,6 +463,11 @@ func ensureObject(t *testing.T, object runtime.Object, klusterlet *operatorapiv1
|
||||
return
|
||||
}
|
||||
|
||||
if !helpers.MapCompare(helpers.GetKlusterletAgentLabels(klusterlet), access.GetLabels()) {
|
||||
t.Errorf("the labels of klusterlet are not synced to %v", access.GetName())
|
||||
return
|
||||
}
|
||||
|
||||
namespace := helpers.AgentNamespace(klusterlet)
|
||||
switch o := object.(type) {
|
||||
case *appsv1.Deployment:
|
||||
@@ -560,6 +565,7 @@ func TestSyncDeploy(t *testing.T) {
|
||||
|
||||
func TestSyncDeploySingleton(t *testing.T) {
|
||||
klusterlet := newKlusterlet("klusterlet", "testns", "cluster1")
|
||||
klusterlet.SetLabels(map[string]string{"test": "test", "abc": "abc"})
|
||||
klusterlet.Spec.DeployOption.Mode = operatorapiv1.InstallModeSingleton
|
||||
bootStrapSecret := newSecret(helpers.BootstrapHubKubeConfig, "testns")
|
||||
hubKubeConfigSecret := newSecret(helpers.HubKubeConfig, "testns")
|
||||
|
||||
@@ -164,6 +164,7 @@ func (r *managedReconcile) createAggregationRule(ctx context.Context, klusterlet
|
||||
},
|
||||
Rules: []rbacv1.PolicyRule{},
|
||||
}
|
||||
aggregateClusterRole.SetLabels(helpers.GetKlusterletAgentLabels(klusterlet))
|
||||
_, createErr := r.managedClusterClients.kubeClient.RbacV1().ClusterRoles().Create(ctx, aggregateClusterRole, metav1.CreateOptions{})
|
||||
return createErr
|
||||
}
|
||||
|
||||
@@ -198,9 +198,10 @@ func (r *runtimeReconcile) createManagedClusterKubeconfig(
|
||||
klusterlet *operatorapiv1.Klusterlet,
|
||||
klusterletNamespace, agentNamespace, saName, secretName string,
|
||||
recorder events.Recorder) error {
|
||||
labels := helpers.GetKlusterletAgentLabels(klusterlet)
|
||||
tokenGetter := helpers.SATokenGetter(ctx, saName, klusterletNamespace, r.managedClusterClients.kubeClient)
|
||||
err := helpers.SyncKubeConfigSecret(ctx, secretName, agentNamespace, "/spoke/config/kubeconfig",
|
||||
r.managedClusterClients.kubeconfig, r.kubeClient.CoreV1(), tokenGetter, recorder)
|
||||
r.managedClusterClients.kubeconfig, r.kubeClient.CoreV1(), tokenGetter, recorder, labels)
|
||||
if err != nil {
|
||||
meta.SetStatusCondition(&klusterlet.Status.Conditions, metav1.Condition{
|
||||
Type: operatorapiv1.ConditionKlusterletApplied, Status: metav1.ConditionFalse, Reason: operatorapiv1.ReasonKlusterletApplyFailed,
|
||||
|
||||
@@ -73,8 +73,16 @@ func (o *Options) RunKlusterletOperator(ctx context.Context, controllerContext *
|
||||
}
|
||||
|
||||
deploymentInformer := informers.NewSharedInformerFactoryWithOptions(kubeClient, 5*time.Minute,
|
||||
informers.WithTweakListOptions(func(options *metav1.ListOptions) {
|
||||
options.LabelSelector = "createdBy=klusterlet"
|
||||
informers.WithTweakListOptions(func(listOptions *metav1.ListOptions) {
|
||||
selector := &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: helpers.AgentLabelKey,
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
},
|
||||
},
|
||||
}
|
||||
listOptions.LabelSelector = metav1.FormatLabelSelector(selector)
|
||||
}))
|
||||
|
||||
// Build operator client and informer
|
||||
|
||||
Reference in New Issue
Block a user