Skip to content

Commit

Permalink
Add an install strategy by label selector (#79)
Browse files Browse the repository at this point in the history
Signed-off-by: Jian Qiu <jqiu@redhat.com>
  • Loading branch information
qiujian16 committed Mar 1, 2022
1 parent 9f09a4f commit f3917ca
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 5 deletions.
26 changes: 22 additions & 4 deletions pkg/addonmanager/controllers/addoninstall/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package addoninstall

import (
"context"
"fmt"

"github.com/openshift/library-go/pkg/controller/factory"
"github.com/openshift/library-go/pkg/operator/events"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
"open-cluster-management.io/addon-framework/pkg/agent"
Expand Down Expand Up @@ -41,7 +41,7 @@ func NewAddonInstallController(
managedClusterLister: clusterInformers.Lister(),
managedClusterAddonLister: addonInformers.Lister(),
agentAddons: agentAddons,
eventRecorder: recorder.WithComponentSuffix(fmt.Sprintf("addon-install-controller")),
eventRecorder: recorder.WithComponentSuffix("addon-install-controller"),
}

return factory.New().WithFilteredEventsInformersQueueKeyFunc(
Expand All @@ -65,14 +65,14 @@ func NewAddonInstallController(
},
clusterInformers.Informer(),
).
WithSync(c.sync).ToController(fmt.Sprintf("addon-install-controller"), recorder)
WithSync(c.sync).ToController("addon-install-controller", recorder)
}

func (c *addonInstallController) sync(ctx context.Context, syncCtx factory.SyncContext) error {
clusterName := syncCtx.QueueKey()
klog.V(4).Infof("Reconciling addon deploy on cluster %q", clusterName)

_, err := c.managedClusterLister.Get(clusterName)
cluster, err := c.managedClusterLister.Get(clusterName)
if errors.IsNotFound(err) {
return nil
}
Expand All @@ -87,6 +87,24 @@ func (c *addonInstallController) sync(ctx context.Context, syncCtx factory.SyncC

switch addon.GetAgentAddonOptions().InstallStrategy.Type {
case agent.InstallAll:
return c.applyAddon(ctx, addonName, clusterName, addon.GetAgentAddonOptions().InstallStrategy.InstallNamespace)
case agent.InstallByLabel:
labelSelector := addon.GetAgentAddonOptions().InstallStrategy.LabelSelector
if labelSelector == nil {
klog.Warningf("installByLabel strategy is set, but label selector is not set")
return nil
}

selector, err := metav1.LabelSelectorAsSelector(labelSelector)
if err != nil {
klog.Warningf("labels selector is not correct: %v", err)
return nil
}

if !selector.Matches(labels.Set(cluster.Labels)) {
return nil
}

return c.applyAddon(ctx, addonName, clusterName, addon.GetAgentAddonOptions().InstallStrategy.InstallNamespace)
}
}
Expand Down
40 changes: 40 additions & 0 deletions pkg/addonmanager/controllers/addoninstall/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/openshift/library-go/pkg/operator/events/eventstesting"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
clienttesting "k8s.io/client-go/testing"
"open-cluster-management.io/addon-framework/pkg/addonmanager/addontesting"
Expand Down Expand Up @@ -34,6 +35,13 @@ func (t *testAgent) GetAgentAddonOptions() agent.AgentAddonOptions {
}
}

func newManagedClusterWithLabel(name, key, value string) *clusterv1.ManagedCluster {
cluster := addontesting.NewManagedCluster(name)
cluster.Labels = map[string]string{key: value}

return cluster
}

func TestReconcile(t *testing.T) {
cases := []struct {
name string
Expand Down Expand Up @@ -77,6 +85,38 @@ func TestReconcile(t *testing.T) {
},
testaddon: &testAgent{name: "test", strategy: agent.InstallAllStrategy("test")},
},
{
name: "selector install strategy with unmatched cluster",
addon: []runtime.Object{},
cluster: []runtime.Object{addontesting.NewManagedCluster("cluster1")},
validateAddonActions: addontesting.AssertNoActions,
testaddon: &testAgent{name: "test", strategy: agent.InstallByLabelStrategy("test", metav1.LabelSelector{
MatchLabels: map[string]string{"mode": "dev"},
})},
},
{
name: "selector install strategy with nil label selector",
addon: []runtime.Object{},
cluster: []runtime.Object{addontesting.NewManagedCluster("cluster1")},
validateAddonActions: addontesting.AssertNoActions,
testaddon: &testAgent{name: "test", strategy: &agent.InstallStrategy{Type: agent.InstallByLabel}},
},
{
name: "selector install strategy with matched cluster",
addon: []runtime.Object{},
cluster: []runtime.Object{newManagedClusterWithLabel("cluster1", "mode", "dev")},
validateAddonActions: func(t *testing.T, actions []clienttesting.Action) {
addontesting.AssertActions(t, actions, "create")
actual := actions[0].(clienttesting.CreateActionImpl).Object
addOn := actual.(*addonapiv1alpha1.ManagedClusterAddOn)
if addOn.Spec.InstallNamespace != "test" {
t.Errorf("Install namespace is not correct, expected test but got %s", addOn.Spec.InstallNamespace)
}
},
testaddon: &testAgent{name: "test", strategy: agent.InstallByLabelStrategy("test", metav1.LabelSelector{
MatchLabels: map[string]string{"mode": "dev"},
})},
},
}

for _, c := range cases {
Expand Down
20 changes: 19 additions & 1 deletion pkg/agent/inteface.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

certificatesv1 "k8s.io/api/certificates/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1"
clusterv1 "open-cluster-management.io/api/cluster/v1"
Expand Down Expand Up @@ -104,7 +105,13 @@ type RegistrationOption struct {

type StrategyType string

const InstallAll StrategyType = "*"
const (
// InstallAll indicate to install addon to all clusters
InstallAll StrategyType = "*"

// InstallByLabel indicate to install addon based on clusters' label
InstallByLabel StrategyType = "LabelSelector"
)

// InstallStrategy is the installation strategy of the manifests prescribed by Manifests(..).
type InstallStrategy struct {
Expand All @@ -113,6 +120,9 @@ type InstallStrategy struct {
Type StrategyType
// InstallNamespace is target deploying namespace in the managed cluster upon automatic addon installation.
InstallNamespace string

// LabelSelector is used to filter clusters based on label. It is only used when strategyType is InstallByLabel
LabelSelector *metav1.LabelSelector
}

type HealthProber struct {
Expand Down Expand Up @@ -173,6 +183,14 @@ func InstallAllStrategy(installNamespace string) *InstallStrategy {
}
}

func InstallByLabelStrategy(installNamespace string, selector metav1.LabelSelector) *InstallStrategy {
return &InstallStrategy{
Type: InstallByLabel,
InstallNamespace: installNamespace,
LabelSelector: &selector,
}
}

// ApprovalAllCSRs returns true for all csrs.
func ApprovalAllCSRs(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn, csr *certificatesv1.CertificateSigningRequest) bool {
return true
Expand Down

0 comments on commit f3917ca

Please sign in to comment.