Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add karmadactl addons subcommand #2134

Merged
merged 1 commit into from
Aug 2, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 38 additions & 0 deletions pkg/karmadactl/addons/addons.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package addons

import (
"fmt"

"github.com/spf13/cobra"
"k8s.io/kubectl/pkg/util/templates"

"github.com/karmada-io/karmada/pkg/karmadactl/addons/install"
)

var (
addonsExamples = templates.Examples(`
# Enable or disable Karmada addons to the karmada-host cluster
%[1]s addons enable karmada-search
`)
)

func init() {
install.Install()
}

// NewCommandAddons enable or disable Karmada addons on karmada-host cluster
func NewCommandAddons(parentCommand string) *cobra.Command {
cmd := &cobra.Command{
Use: "addons",
Short: "Enable or disable a Karmada addon",
Long: "Enable or disable a Karmada addon",
Example: fmt.Sprintf(addonsExamples, parentCommand),
}

addonsParentCommand := fmt.Sprintf("%s %s", parentCommand, "addons")
cmd.AddCommand(NewCmdAddonsList(addonsParentCommand))
cmd.AddCommand(NewCmdAddonsEnable(addonsParentCommand))
cmd.AddCommand(NewCmdAddonsDisable(addonsParentCommand))

return cmd
}
83 changes: 83 additions & 0 deletions pkg/karmadactl/addons/descheduler/descheduler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package descheduler

import (
"context"
"fmt"

appsv1 "k8s.io/api/apps/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kuberuntime "k8s.io/apimachinery/pkg/runtime"
clientsetscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/klog/v2"

addoninit "github.com/karmada-io/karmada/pkg/karmadactl/addons/init"
addonutils "github.com/karmada-io/karmada/pkg/karmadactl/addons/utils"
"github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/kubernetes"
initutils "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils"
)

var karmadaDeschedulerLabels = map[string]string{"app": addoninit.DeschedulerResourceName}

// AddonDescheduler describe the descheduler addon command process
var AddonDescheduler = &addoninit.Addon{
Name: addoninit.DeschedulerResourceName,
Status: status,
Enable: enableDescheduler,
Disable: disableDescheduler,
}

var status = func(opts *addoninit.CommandAddonsListOption) (string, error) {
deployment, err := opts.KubeClientSet.AppsV1().Deployments(opts.Namespace).Get(context.TODO(), addoninit.DeschedulerResourceName, metav1.GetOptions{})
if err != nil {
if apierrors.IsNotFound(err) {
return addoninit.AddonDisabledStatus, nil
}
return addoninit.AddonUnknownStatus, err
}
if deployment.Status.Replicas != deployment.Status.ReadyReplicas ||
deployment.Status.Replicas != deployment.Status.AvailableReplicas {
return addoninit.AddonUnhealthyStatus, nil
}

return addoninit.AddonEnabledStatus, nil
}

var enableDescheduler = func(opts *addoninit.CommandAddonsEnableOption) error {
// install karmada descheduler deployment on host cluster
karmadaDeschedulerDeploymentBytes, err := addonutils.ParseTemplate(karmadaDeschedulerDeployment, DeploymentReplace{
Namespace: opts.Namespace,
Replicas: &opts.KarmadaDeschedulerReplicas,
Image: opts.KarmadaDeschedulerImage,
})
if err != nil {
return fmt.Errorf("error when parsing karmada descheduler deployment template :%v", err)
}

karmadaDeschedulerDeployment := &appsv1.Deployment{}
if err := kuberuntime.DecodeInto(clientsetscheme.Codecs.UniversalDecoder(), karmadaDeschedulerDeploymentBytes, karmadaDeschedulerDeployment); err != nil {
return fmt.Errorf("decode descheduler deployment error: %v", err)
}

if err := addonutils.CreateOrUpdateDeployment(opts.KubeClientSet, karmadaDeschedulerDeployment); err != nil {
return fmt.Errorf("create karmada descheduler deployment error: %v", err)
}

if err := kubernetes.WaitPodReady(opts.KubeClientSet, opts.Namespace, initutils.MapToString(karmadaDeschedulerLabels), opts.WaitPodReadyTimeout); err != nil {
return fmt.Errorf("wait karmada descheduler pod timeout: %v", err)
}

klog.Infof("Install karmada descheduler deployment on host cluster successfully")
return nil
}

var disableDescheduler = func(opts *addoninit.CommandAddonsDisableOption) error {
// uninstall karmada descheduler deployment on host cluster
deployClient := opts.KubeClientSet.AppsV1().Deployments(opts.Namespace)
if err := deployClient.Delete(context.TODO(), addoninit.DeschedulerResourceName, metav1.DeleteOptions{}); err != nil && !apierrors.IsNotFound(err) {
return err
}

klog.Infof("Uninstall karmada descheduler deployment on host cluster successfully")
return nil
}
59 changes: 59 additions & 0 deletions pkg/karmadactl/addons/descheduler/manifests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package descheduler

const karmadaDeschedulerDeployment = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: karmada-descheduler
namespace: {{ .Namespace }}
labels:
app: karmada-descheduler
spec:
selector:
matchLabels:
app: karmada-descheduler
replicas: {{ .Replicas }}
template:
metadata:
labels:
app: karmada-descheduler
spec:
tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
containers:
- name: karmada-descheduler
image: {{ .Image }}
imagePullPolicy: IfNotPresent
command:
- /bin/karmada-descheduler
- --kubeconfig=/etc/kubeconfig
- --bind-address=0.0.0.0
- --leader-elect-resource-namespace={{ .Namespace }}
- --v=4
livenessProbe:
httpGet:
path: /healthz
port: 10358
scheme: HTTP
failureThreshold: 3
initialDelaySeconds: 15
periodSeconds: 15
timeoutSeconds: 5
volumeMounts:
- name: kubeconfig
subPath: kubeconfig
mountPath: /etc/kubeconfig
volumes:
- name: kubeconfig
secret:
secretName: kubeconfig
`

// DeploymentReplace is a struct to help to concrete
// the karamda-descheduler deployment bytes with the deployment template
type DeploymentReplace struct {
Namespace string
Replicas *int32
Image string
}
61 changes: 61 additions & 0 deletions pkg/karmadactl/addons/disable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package addons

import (
"fmt"

"github.com/spf13/cobra"
"k8s.io/kubectl/pkg/util/templates"

addoninit "github.com/karmada-io/karmada/pkg/karmadactl/addons/init"
)

var (
disableExample = templates.Examples(`
# Disable Karmada all addons except karmada-scheduler-estimator on Kubernetes cluster
%[1]s disable all

# Disable Karmada search on Kubernetes cluster
%[1]s disable karmada-search

# Disable Karmada search and descheduler on Kubernetes cluster
%[1]s disable karmada-search karmada-descheduler

# Disable karmada search and scheduler-estimator of member1 cluster to the kubernetes cluster
%[1]s disable karmada-search karmada-scheduler-estimator --cluster member1

# Specify the host cluster kubeconfig
%[1]s disable Karmada-search --kubeconfig /root/.kube/config

# Specify the Karmada control plane kubeconfig
%[1]s disable karmada-search --karmada-kubeconfig /etc/karmada/karmada-apiserver.config

# Sepcify the namespace where Karmada components are installed
%[1]s disable karmada-search --namespace karmada-system
`)
)

// NewCmdAddonsDisable disable Karmada addons on Kubernetes
func NewCmdAddonsDisable(parentCommand string) *cobra.Command {
opts := addoninit.CommandAddonsDisableOption{}
cmd := &cobra.Command{
Use: "disable",
Short: "Disable karmada addons from Kubernetes",
Long: "Disable Karmada addons from Kubernetes",
Example: fmt.Sprintf(disableExample, parentCommand),
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := opts.Complete(); err != nil {
return err
}
if err := opts.Validate(args); err != nil {
return err
}
if err := opts.Run(args); err != nil {
return err
}
return nil
},
}
opts.GlobalCommandOptions.AddFlags(cmd.PersistentFlags())
return cmd
}
84 changes: 84 additions & 0 deletions pkg/karmadactl/addons/enable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package addons

import (
"fmt"

"github.com/spf13/cobra"
"k8s.io/klog/v2"
"k8s.io/kubectl/pkg/util/templates"

addoninit "github.com/karmada-io/karmada/pkg/karmadactl/addons/init"
"github.com/karmada-io/karmada/pkg/version"
)

var (
enableExample = templates.Examples(`
# Enable Karmada all addons except karmada-scheduler-estimator to Kubernetes cluster
%[1]s enable all

# Enable Karmada search to the Kubernetes cluster
%[1]s enable karmada-search

# Enable karmada search and descheduler to the kubernetes cluster
%[1]s enable karmada-search karmada-descheduler

# Enable karmada search and scheduler-estimator of cluster member1 to the kubernetes cluster
%[1]s enable karmada-search karmada-scheduler-estimator -C member1 --member-kubeconfig /etc/karmada/member.config --member-context member1

# Specify the host cluster kubeconfig
%[1]s enable karmada-search --kubeconfig /root/.kube/config

# Specify the Karmada control plane kubeconfig
%[1]s enable karmada-search --karmada-kubeconfig /etc/karmada/karmada-apiserver.config

# Specify the karmada-search image
%[1]s enable karmada-search --karmada-search-image swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-scheduler-estimator:latest

# Sepcify the namespace where Karmada components are installed
%[1]s enable karmada-search --namespace karmada-system
`)
)

// NewCmdAddonsEnable enable Karmada addons on Kubernetes
func NewCmdAddonsEnable(parentCommand string) *cobra.Command {
opts := addoninit.CommandAddonsEnableOption{}
cmd := &cobra.Command{
Use: "enable",
Short: "Enable Karmada addons from Kubernetes",
Long: "Enable Karmada addons from Kubernetes",
Example: fmt.Sprintf(enableExample, parentCommand),
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if err := opts.Complete(); err != nil {
return err
}
if err := opts.Validate(args); err != nil {
return err
}
if err := opts.Run(args); err != nil {
return err
}
return nil
},
}

releaseVer, err := version.ParseGitVersion(version.Get().GitVersion)
if err != nil {
klog.Infof("No default release version found. build version: %s", version.Get().String())
releaseVer = &version.ReleaseVersion{} // initialize to avoid panic
}

flags := cmd.PersistentFlags()
opts.GlobalCommandOptions.AddFlags(flags)
flags.IntVar(&opts.WaitPodReadyTimeout, "pod-timeout", 30, "Wait pod ready timeout.")
flags.IntVar(&opts.WaitAPIServiceReadyTimeout, "apiservice-timeout", 30, "Wait apiservice ready timeout.")
flags.StringVar(&opts.KarmadaSearchImage, "karmada-search-image", fmt.Sprintf("swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-search:%s", releaseVer.PatchRelease()), "karmada search image")
flags.Int32Var(&opts.KarmadaSearchReplicas, "karmada-search-replicas", 1, "Karmada search replica set")
flags.StringVar(&opts.KarmadaDeschedulerImage, "karmada-descheduler-image", fmt.Sprintf("swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-descheduler:%s", releaseVer.PatchRelease()), "karmada descheduler image")
flags.Int32Var(&opts.KarmadaDeschedulerReplicas, "karmada-descheduler-replicas", 1, "Karmada descheduler replica set")
flags.StringVar(&opts.KarmadaSchedulerEstimatorImage, "karmada-scheduler-estimator-image", fmt.Sprintf("swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-scheduler-estimator:%s", releaseVer.PatchRelease()), "karmada scheduler-estimator image")
flags.Int32Var(&opts.KarmadaEstimatorReplicas, "karmada-estimator-replicas", 1, "Karmada scheduler estimator replica set")
flags.StringVar(&opts.MemberKubeConfig, "member-kubeconfig", "", "Member cluster's kubeconfig which to deploy scheduler estimator")
flags.StringVar(&opts.MemberContext, "member-context", "", "Member cluster's context which to deploy scheduler estimator")
return cmd
}