From f349f5e768c0c149b711c22c37d1cb65f5065101 Mon Sep 17 00:00:00 2001 From: ymmt Date: Fri, 30 Apr 2021 02:07:17 +0000 Subject: [PATCH] kubectl-moco: add switchover subcommand --- cmd/kubectl-moco/cmd/credential.go | 2 +- cmd/kubectl-moco/cmd/mysql.go | 2 +- cmd/kubectl-moco/cmd/switchover.go | 50 ++++++++++++++++++++++++++++++ docs/kubectl-moco.md | 4 +++ docs/usage.md | 7 ++--- e2e/replication_test.go | 2 +- e2e/upgrade_test.go | 2 +- 7 files changed, 60 insertions(+), 9 deletions(-) create mode 100644 cmd/kubectl-moco/cmd/switchover.go diff --git a/cmd/kubectl-moco/cmd/credential.go b/cmd/kubectl-moco/cmd/credential.go index 85650e3f1..0c56e155f 100644 --- a/cmd/kubectl-moco/cmd/credential.go +++ b/cmd/kubectl-moco/cmd/credential.go @@ -14,7 +14,7 @@ var credentialConfig struct { // credentialCmd represents the credential command var credentialCmd = &cobra.Command{ - Use: "credential ", + Use: "credential CLUSTER_NAME", Short: "Fetch the credential of a specified user", Long: "Fetch the credential of a specified user.", Args: cobra.ExactArgs(1), diff --git a/cmd/kubectl-moco/cmd/mysql.go b/cmd/kubectl-moco/cmd/mysql.go index 543bd40db..6e279a797 100644 --- a/cmd/kubectl-moco/cmd/mysql.go +++ b/cmd/kubectl-moco/cmd/mysql.go @@ -29,7 +29,7 @@ var mysqlConfig struct { // mysqlCmd represents the mysql command var mysqlCmd = &cobra.Command{ - Use: "mysql [COMMANDS]", + Use: "mysql CLUSTER_NAME -- [COMMANDS]", Short: "Run mysql command in a specified MySQL instance", Long: "Run mysql command in a specified MySQL instance.", Args: cobra.MinimumNArgs(1), diff --git a/cmd/kubectl-moco/cmd/switchover.go b/cmd/kubectl-moco/cmd/switchover.go new file mode 100644 index 000000000..0496cb0f3 --- /dev/null +++ b/cmd/kubectl-moco/cmd/switchover.go @@ -0,0 +1,50 @@ +package cmd + +import ( + "context" + "errors" + + mocov1beta1 "github.com/cybozu-go/moco/api/v1beta1" + "github.com/cybozu-go/moco/pkg/constants" + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" +) + +var switchoverCmd = &cobra.Command{ + Use: "switchover CLUSTER_NAME", + Short: "Switch the primary instance", + Long: "Switch the primary instance to one of the replicas.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return switchover(cmd.Context(), args[0]) + }, +} + +func switchover(ctx context.Context, name string) error { + cluster := &mocov1beta1.MySQLCluster{} + if err := kubeClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, cluster); err != nil { + return err + } + + if cluster.Spec.Replicas == 1 { + return errors.New("single-instance cluster is not able to switch") + } + + podName := cluster.PodName(cluster.Status.CurrentPrimaryIndex) + pod := &corev1.Pod{} + if err := kubeClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: podName}, pod); err != nil { + return err + } + + if pod.Annotations == nil { + pod.Annotations = make(map[string]string) + } + pod.Annotations[constants.AnnDemote] = "true" + + return kubeClient.Update(ctx, pod) +} + +func init() { + rootCmd.AddCommand(switchoverCmd) +} diff --git a/docs/kubectl-moco.md b/docs/kubectl-moco.md index 52439edc9..e3cf03661 100644 --- a/docs/kubectl-moco.md +++ b/docs/kubectl-moco.md @@ -65,3 +65,7 @@ Fetch the credential information of a specified user | ------------------ | --------------- | ------------------------------------------ | | `-u, --mysql-user` | `moco-readonly` | Fetch the credential of the specified user | | `--format` | `plain` | Output format: `plain` or `mycnf` | + +## `kubectl moco switchover CLUSTER_NAME` + +Switch the primary instance to one of the replicas. diff --git a/docs/usage.md b/docs/usage.md index f14e4ddab..fe14bb024 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -399,11 +399,8 @@ Switchver is an operation to change the live primary to one of the replicas. MOCO automatically switch the primary when the Pod of the primary instance is to be deleted. -Users can manually trigger a switchover by annotating the Pod of the primary instance with `moco.cybozu.com/demote: true`. You can use `kubectl` to do this: - -```console -$ kubectl annotate mysqlcluster moco.cybozu.com/demote=true -``` +Users can manually trigger a switchover with `kubectl moco switchover CLUSTER_NAME`. +Read [`kubectl-moco.md`](kubectl-moco.md) for details. ### Failover diff --git a/e2e/replication_test.go b/e2e/replication_test.go index d2149bec0..fe84761d2 100644 --- a/e2e/replication_test.go +++ b/e2e/replication_test.go @@ -114,7 +114,7 @@ var _ = Context("replication", func() { }) It("should switch the primary if requested", func() { - kubectlSafe(nil, "-n", "repl", "annotate", "pod", "moco-test-0", "moco.cybozu.com/demote=true") + kubectlSafe(nil, "moco", "-n", "repl", "switchover", "test") Eventually(func() int { cluster, err := getCluster("repl", "test") if err != nil { diff --git a/e2e/upgrade_test.go b/e2e/upgrade_test.go index 4bdf33778..6933a6c94 100644 --- a/e2e/upgrade_test.go +++ b/e2e/upgrade_test.go @@ -70,7 +70,7 @@ var _ = Context("upgrade", func() { fmt.Printf("The current primary = %d\n", primary) By("doing a switchover") - kubectlSafe(nil, "annotate", "-n", "upgrade", "pod", cluster.PodName(primary), "moco.cybozu.com/demote=true") + kubectlSafe(nil, "moco", "-n", "upgrade", "switchover", "test") Eventually(func() error { var err error cluster, err = getCluster("upgrade", "test")