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

[cli] migrate mysqlctl and mysqlctld to cobra #13946

Merged
merged 11 commits into from
Sep 21, 2023
Merged
71 changes: 71 additions & 0 deletions go/cmd/mysqlctl/command/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
Copyright 2023 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package command

import (
"context"
"fmt"
"time"

"github.com/spf13/cobra"

"vitess.io/vitess/go/vt/mysqlctl"
)

var Init = &cobra.Command{
Use: "init",
Short: "Initializes the directory structure and starts mysqld.",
Long: "Bootstraps a new `mysqld` instance, initializes its data directory, and starts the instance.\n" +
"The MySQL version and flavor will be auto-detected, with a minimal configuration file applied.",
Example: `mysqlctl \
--alsologtostderr \
--tablet_uid 101 \
--mysql_port 12345 \
init`,
Args: cobra.NoArgs,
RunE: commandInit,
}

var initArgs = struct {
WaitTime time.Duration
InitDbSQLFile string
}{
WaitTime: 5 * time.Minute,
}

func commandInit(cmd *cobra.Command, args []string) error {
// Generate my.cnf from scratch and use it to find mysqld.
mysqld, cnf, err := mysqlctl.CreateMysqldAndMycnf(tabletUID, mysqlSocket, mysqlPort)
if err != nil {
return fmt.Errorf("failed to initialize mysql config: %v", err)
}
defer mysqld.Close()

ctx, cancel := context.WithTimeout(context.Background(), initArgs.WaitTime)
defer cancel()
if err := mysqld.Init(ctx, cnf, initArgs.InitDbSQLFile); err != nil {
return fmt.Errorf("failed init mysql: %v", err)
}
return nil
}

func init() {
Init.Flags().DurationVar(&initArgs.WaitTime, "wait_time", initArgs.WaitTime, "How long to wait for mysqld startup.")
Init.Flags().StringVar(&initArgs.InitDbSQLFile, "init_db_sql_file", initArgs.InitDbSQLFile, "Path to .sql file to run after mysqld initiliaztion.")

Root.AddCommand(Init)
}
57 changes: 57 additions & 0 deletions go/cmd/mysqlctl/command/init_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2023 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package command

import (
"fmt"

"github.com/spf13/cobra"

"vitess.io/vitess/go/vt/mysqlctl"
)

var InitConfig = &cobra.Command{
Use: "init_config",
Short: "Initializes the directory structure, creates my.cnf file, but does not start mysqld.",
Long: "Bootstraps the configuration for a new `mysqld` instance and initializes its data directory.\n" +
"This command is the same as `init` except the `mysqld` server will not be started.",
Example: `mysqlctl \
--alsologtostderr \
--tablet_uid 101 \
--mysql_port 12345 \
init_config`,
Args: cobra.NoArgs,
RunE: commandInitConfig,
}

func commandInitConfig(cmd *cobra.Command, args []string) error {
// Generate my.cnf from scratch and use it to find mysqld.
mysqld, cnf, err := mysqlctl.CreateMysqldAndMycnf(tabletUID, mysqlSocket, mysqlPort)
if err != nil {
return fmt.Errorf("failed to initialize mysql config: %v", err)
}
defer mysqld.Close()
if err := mysqld.InitConfig(cnf); err != nil {
return fmt.Errorf("failed to init mysql config: %v", err)
}

return nil
}

func init() {
Root.AddCommand(InitConfig)
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package main
package command

// This plugin imports Prometheus to allow for instrumentation
// with the Prometheus client library
Expand Down
74 changes: 74 additions & 0 deletions go/cmd/mysqlctl/command/position.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
Copyright 2023 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package command

import (
"fmt"

"github.com/spf13/cobra"

"vitess.io/vitess/go/mysql/replication"
)

var Position = &cobra.Command{
Use: "position <operation> <pos1> <pos2 | gtid>",
Short: "Compute operations on replication positions",
Args: cobra.MatchAll(cobra.ExactArgs(3), func(cmd *cobra.Command, args []string) error {
switch args[0] {
case "equal", "at_least", "append":
default:
return fmt.Errorf("invalid operation %s (choices are 'equal', 'at_least', 'append')", args[0])
}

return nil
}),
RunE: commandPosition,
}

func commandPosition(cmd *cobra.Command, args []string) error {
pos1, err := replication.DecodePosition(args[1])
if err != nil {
return err
}

switch args[0] {
case "equal":
pos2, err := replication.DecodePosition(args[2])
if err != nil {
return err
}
fmt.Println(pos1.Equal(pos2))
case "at_least":
pos2, err := replication.DecodePosition(args[2])
if err != nil {
return err
}
fmt.Println(pos1.AtLeast(pos2))
case "append":
gtid, err := replication.DecodeGTID(args[2])
if err != nil {
return err
}
fmt.Println(replication.AppendGTID(pos1, gtid))
}

return nil
}

func init() {
Root.AddCommand(Position)
}
58 changes: 58 additions & 0 deletions go/cmd/mysqlctl/command/reinit_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
Copyright 2023 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package command

import (
"context"
"fmt"

"github.com/spf13/cobra"

"vitess.io/vitess/go/vt/mysqlctl"
)

var ReinitConfig = &cobra.Command{
Use: "reinit_config",
Short: "Reinitializes my.cnf file with new server_id.",
Long: "Regenerate new configuration files for an existing `mysqld` instance (generating new server_id and server_uuid values).\n" +
"This could be helpful to revert configuration changes, or to pick up changes made to the bundled config in newer Vitess versions.",
Example: `mysqlctl \
--alsologtostderr \
--tablet_uid 101 \
--mysql_port 12345 \
reinit_config`,
Args: cobra.NoArgs,
RunE: commandReinitConfig,
}

func commandReinitConfig(cmd *cobra.Command, args []string) error {
// There ought to be an existing my.cnf, so use it to find mysqld.
mysqld, cnf, err := mysqlctl.OpenMysqldAndMycnf(tabletUID)
if err != nil {
return fmt.Errorf("failed to find mysql config: %v", err)
}
defer mysqld.Close()

if err := mysqld.ReinitConfig(context.TODO(), cnf); err != nil {
return fmt.Errorf("failed to reinit mysql config: %v", err)
}
return nil
}

func init() {
Root.AddCommand(ReinitConfig)
}
77 changes: 77 additions & 0 deletions go/cmd/mysqlctl/command/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Copyright 2023 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package command

import (
"fmt"

"github.com/spf13/cobra"

"vitess.io/vitess/go/acl"
vtcmd "vitess.io/vitess/go/cmd"
"vitess.io/vitess/go/vt/dbconfigs"
"vitess.io/vitess/go/vt/logutil"
"vitess.io/vitess/go/vt/servenv"
)

var (
mysqlPort = 3306
tabletUID = uint32(41983)
mysqlSocket string

Root = &cobra.Command{
Use: "mysqlctl",
Short: "mysqlctl initializes and controls mysqld with Vitess-specific configuration.",
Long: "`mysqlctl` is a command-line client used for managing `mysqld` instances.\n\n" +

"It is responsible for bootstrapping tasks such as generating a configuration file for `mysqld` and initializing the instance and its data directory.\n" +
"The `mysqld_safe` watchdog is utilized when present.\n" +
"This helps ensure that `mysqld` is automatically restarted after failures.",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
if err := servenv.CobraPreRunE(cmd, args); err != nil {
return nil
}

if vtcmd.IsRunningAsRoot() {
return fmt.Errorf("mysqlctl cannot be run as root. Please run as a different user")
}

return nil
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
logutil.Flush()
},
Version: servenv.AppVersion.String(),
}
)

func init() {
servenv.RegisterDefaultSocketFileFlags()
servenv.RegisterFlags()
servenv.RegisterServiceMapFlag()

// mysqlctl only starts and stops mysql, only needs dba.
dbconfigs.RegisterFlags(dbconfigs.Dba)

servenv.MovePersistentFlagsToCobraCommand(Root)

Root.PersistentFlags().IntVar(&mysqlPort, "mysql_port", mysqlPort, "MySQL port.")
Root.PersistentFlags().Uint32Var(&tabletUID, "tablet_uid", tabletUID, "Tablet UID.")
Root.PersistentFlags().StringVar(&mysqlSocket, "mysql_socket", mysqlSocket, "Path to the mysqld socket file.")

acl.RegisterFlags(Root.PersistentFlags())
}
Loading