Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion pkg/cmd/addon/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ package addon
import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"open-cluster-management.io/clusteradm/pkg/cmd/addon/disable"
"open-cluster-management.io/clusteradm/pkg/cmd/addon/enable"

genericclioptionsclusteradm "open-cluster-management.io/clusteradm/pkg/genericclioptions"
)

Expand All @@ -17,6 +17,7 @@ func NewCmd(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, stream
}

cmd.AddCommand(enable.NewCmd(clusteradmFlags, streams))
cmd.AddCommand(disable.NewCmd(clusteradmFlags, streams))

return cmd
}
52 changes: 52 additions & 0 deletions pkg/cmd/addon/disable/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright Contributors to the Open Cluster Management project
package disable

import (
"fmt"

genericclioptionsclusteradm "open-cluster-management.io/clusteradm/pkg/genericclioptions"
clusteradmhelpers "open-cluster-management.io/clusteradm/pkg/helpers"

"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
)

var example = `
# Disanable addon on a cluster in speccified a namespace
%[1]s addon disable --name application-manager --ns namespace --cluster cluster1,cluster2
`

// NewCmd...
func NewCmd(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, streams genericclioptions.IOStreams) *cobra.Command {
o := newOptions(clusteradmFlags, streams)

cmd := &cobra.Command{
Use: "disable",
Short: "disable specified addon on specified managed cluster",
Example: fmt.Sprintf(example, clusteradmhelpers.GetExampleHeader()),
SilenceUsage: true,
PreRunE: func(c *cobra.Command, args []string) error {
clusteradmhelpers.DryRunMessage(clusteradmFlags.DryRun)

return nil
},
RunE: func(c *cobra.Command, args []string) error {
if err := o.complete(c, args); err != nil {
return err
}
if err := o.validate(); err != nil {
return err
}
if err := o.run(); err != nil {
return err
}

return nil
},
}

cmd.Flags().StringSliceVar(&o.names, "name", []string{}, "Names of the add-on to deploy (comma separated)")
cmd.Flags().StringSliceVar(&o.clusters, "cluster", []string{}, "Names of the managed cluster to deploy the add-on to (comma separated)")

return cmd
}
100 changes: 100 additions & 0 deletions pkg/cmd/addon/disable/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright Contributors to the Open Cluster Management project
package disable

import (
"context"
"fmt"

"k8s.io/apimachinery/pkg/api/errors"

"github.com/spf13/cobra"
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
addonclient "open-cluster-management.io/api/client/addon/clientset/versioned"
clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned"
"open-cluster-management.io/clusteradm/pkg/helpers"
)

func (o *Options) complete(cmd *cobra.Command, args []string) (err error) {
klog.V(1).InfoS("disable options:", "dry-run", o.ClusteradmFlags.DryRun, "names", o.names, "clusters", o.clusters)

return nil
}

func (o *Options) validate() (err error) {
if len(o.names) == 0 {
return fmt.Errorf("names is missing")
}

if len(o.clusters) == 0 {
return fmt.Errorf("clusters is misisng")
}
return nil
}

func (o *Options) run() (err error) {
addons := sets.NewString(o.names...)
clusters := sets.NewString(o.clusters...)

klog.V(3).InfoS("values:", "addon", addons, "clusters", clusters)

restConfig, err := o.ClusteradmFlags.KubectlFactory.ToRESTConfig()
if err != nil {
return err
}
clusterClient, err := clusterclientset.NewForConfig(restConfig)
if err != nil {
return err
}

addonClient, err := addonclient.NewForConfig(restConfig)
if err != nil {
return err
}

kubeClient, apiExtensionsClient, dynamicClient, err := helpers.GetClients(o.ClusteradmFlags.KubectlFactory)
if err != nil {
return err
}

return o.runWithClient(clusterClient, addonClient, kubeClient, apiExtensionsClient, dynamicClient, o.ClusteradmFlags.DryRun, addons.List(), clusters.List())
}

func (o *Options) runWithClient(clusterClient clusterclientset.Interface,
addonClient addonclient.Interface,
kubeClient kubernetes.Interface,
apiExtensionsClient apiextensionsclient.Interface,
dynamicClient dynamic.Interface,
dryRun bool,
addons []string,
clusters []string) error {

for _, clusterName := range clusters {
_, err := clusterClient.ClusterV1().ManagedClusters().Get(context.TODO(),
clusterName,
metav1.GetOptions{})
if err != nil {
return err
}
}

for _, addon := range addons {
for _, clusterName := range clusters {
err := addonClient.AddonV1alpha1().ManagedClusterAddOns(clusterName).Delete(context.TODO(),
addon,
metav1.DeleteOptions{})
if err != nil {
if !errors.IsNotFound(err) {
return err
}
}
fmt.Fprintf(o.Streams.Out, "Undeploying %s add-on in managed cluster: %s.\n", addon, clusterName)
}
}

return nil
}
127 changes: 127 additions & 0 deletions pkg/cmd/addon/disable/exec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright Contributors to the Open Cluster Management project
package disable

import (
"context"
"fmt"
"os"

"github.com/onsi/ginkgo"
"github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/rand"
"k8s.io/cli-runtime/pkg/genericclioptions"

clusterapiv1 "open-cluster-management.io/api/cluster/v1"

"open-cluster-management.io/clusteradm/pkg/cmd/addon/enable"
"open-cluster-management.io/clusteradm/pkg/cmd/addon/enable/scenario"

"open-cluster-management.io/clusteradm/pkg/helpers/apply"
)

var _ = ginkgo.Describe("addon disable", func() {
var cluster1Name string
var cluster2Name string
var err error

appMgrAddonName := "application-manager"

ginkgo.BeforeEach(func() {
cluster1Name = fmt.Sprintf("cluster-%s", rand.String(5))
cluster2Name = fmt.Sprintf("cluster-%s", rand.String(5))
})

assertCreatingClusters := func(clusterName string) {
ginkgo.By(fmt.Sprintf("Create %s cluster", clusterName))

cluster := &clusterapiv1.ManagedCluster{
ObjectMeta: metav1.ObjectMeta{
Name: clusterName,
},
}

_, err = clusterClient.ClusterV1().ManagedClusters().Create(context.Background(), cluster, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred())

ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: clusterName,
},
}
_, err := kubeClient.CoreV1().Namespaces().Create(context.Background(), ns, metav1.CreateOptions{})
gomega.Expect(err).ToNot(gomega.HaveOccurred(), "creat cluster error")
}

streams := genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}

assertEnableAddon := func(addons []string, clusters []string, ns string) {

reader := scenario.GetScenarioResourcesReader()
applierBuilder := &apply.ApplierBuilder{}
applier := applierBuilder.WithClient(kubeClient, apiExtensionsClient, dynamicClient).Build()

for _, addon := range addons {
for _, clus := range clusters {
ginkgo.By(fmt.Sprintf("Enableing %s addon on %s cluster in %s namespce", addon, clus, ns))

cai := enable.NewClusterAddonInfo(clus, ns, addon)
_, err := applier.ApplyCustomResources(reader, cai, false, "", "addons/app/addon.yaml")
gomega.Expect(err).ToNot(gomega.HaveOccurred(), "enable addon error")
fmt.Fprintf(streams.Out, "Deploying %s add-on to namespaces %s of managed cluster: %s.\n", addon, ns, clus)
}
}
}

ginkgo.Context("runWithClient", func() {

ginkgo.It("Should disable application-manager ManagedClusterAddOn in ManagedCluster namespace successfully", func() {
assertCreatingClusters(cluster1Name)

addons := []string{appMgrAddonName}
clusters := []string{cluster1Name}
assertEnableAddon([]string{appMgrAddonName}, []string{cluster1Name}, "default")

o := Options{
Streams: streams,
}

err := o.runWithClient(clusterClient, addonClient, kubeClient, apiExtensionsClient, dynamicClient, false, addons, clusters)
gomega.Expect(err).ToNot(gomega.HaveOccurred())
})

ginkgo.It("Should disable application-manager ManagedClusterAddOns in each ManagedCluster namespace successfully", func() {
assertCreatingClusters(cluster1Name)
assertCreatingClusters(cluster2Name)

addons := []string{appMgrAddonName}
clusters := []string{cluster1Name, cluster2Name}
assertEnableAddon(addons, clusters, "default")

o := Options{
Streams: streams,
}

err := o.runWithClient(clusterClient, addonClient, kubeClient, apiExtensionsClient, dynamicClient, false, addons, clusters)
gomega.Expect(err).ToNot(gomega.HaveOccurred())
})

ginkgo.It("Should not disable a ManagedClusterAddOn because ManagedCluster doesn't exist", func() {
assertCreatingClusters(cluster1Name)

addons := []string{appMgrAddonName}
clusters := []string{cluster1Name}
assertEnableAddon(addons, clusters, "default")

wrongCluster := "no-such-addon"
wrongClusters := []string{wrongCluster}
o := Options{
Streams: streams,
}

err := o.runWithClient(clusterClient, addonClient, kubeClient, apiExtensionsClient, dynamicClient, false, addons, wrongClusters)
gomega.Expect(err).To(gomega.HaveOccurred())
})
})
})
25 changes: 25 additions & 0 deletions pkg/cmd/addon/disable/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright Contributors to the Open Cluster Management project
package disable

import (
"k8s.io/cli-runtime/pkg/genericclioptions"
genericclioptionsclusteradm "open-cluster-management.io/clusteradm/pkg/genericclioptions"
)

type Options struct {
//ClusteradmFlags: The generic optiosn from the clusteradm cli-runtime.
ClusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags
//A list of comma separated addon names
names []string
//A list of comma separated cluster names
clusters []string

Streams genericclioptions.IOStreams
}

func newOptions(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, streams genericclioptions.IOStreams) *Options {
return &Options{
ClusteradmFlags: clusteradmFlags,
Streams: streams,
}
}
70 changes: 70 additions & 0 deletions pkg/cmd/addon/disable/suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright Contributors to the Open Cluster Management project
package disable

import (
"path/filepath"
"testing"

"github.com/onsi/ginkgo"
"github.com/onsi/gomega"

apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/envtest"

addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned"
clusterv1client "open-cluster-management.io/api/client/cluster/clientset/versioned"
)

var testEnv *envtest.Environment
var restConfig *rest.Config
var kubeClient kubernetes.Interface
var apiExtensionsClient apiextensionsclient.Interface
var dynamicClient dynamic.Interface
var clusterClient clusterv1client.Interface
var addonClient addonv1alpha1client.Interface

func TestIntegrationEnableAddons(t *testing.T) {
gomega.RegisterFailHandler(ginkgo.Fail)
ginkgo.RunSpecs(t, "Integration Disable Addons Suite")
}

var _ = ginkgo.BeforeSuite(func(done ginkgo.Done) {
ginkgo.By("bootstrapping test environment")

// start a kube-apiserver
testEnv = &envtest.Environment{
ErrorIfCRDPathMissing: true,
CRDDirectoryPaths: []string{
filepath.Join("..", "..", "..", "..", "vendor", "open-cluster-management.io", "api", "cluster", "v1"),
filepath.Join("..", "..", "..", "..", "vendor", "open-cluster-management.io", "api", "addon", "v1alpha1"),
},
}

cfg, err := testEnv.Start()
gomega.Expect(err).ToNot(gomega.HaveOccurred())
gomega.Expect(cfg).ToNot(gomega.BeNil())

kubeClient, err = kubernetes.NewForConfig(cfg)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
apiExtensionsClient, err = apiextensionsclient.NewForConfig(cfg)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
dynamicClient, err = dynamic.NewForConfig(cfg)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
clusterClient, err = clusterv1client.NewForConfig(cfg)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
addonClient, err = addonv1alpha1client.NewForConfig(cfg)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

restConfig = cfg
close(done)
}, 60)

var _ = ginkgo.AfterSuite(func() {
ginkgo.By("tearing down the test environment")

err := testEnv.Stop()
gomega.Expect(err).ToNot(gomega.HaveOccurred())
})
Loading