Skip to content

Commit

Permalink
Sync from server repo (f6f6ed13bc4)
Browse files Browse the repository at this point in the history
  • Loading branch information
releng committed Oct 11, 2024
1 parent 12b86bb commit ef6bed4
Show file tree
Hide file tree
Showing 20 changed files with 1,318 additions and 222 deletions.
46 changes: 44 additions & 2 deletions commands/cluster_command_launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ const (
targetPasswordFileKey = "targetPasswordFile"
targetConnFlag = "target-conn"
targetConnKey = "targetConn"
targetKeyFileFlag = "target-key-file"
targetKeyFileKey = "targetKeyFile"
targetCertFileFlag = "target-cert-file"
targetCertFileKey = "targetCertFile"
targetCaCertFileFlag = "target-ca-cert-file"
targetCaCertFileKey = "targetCaCertFile"
targetTLSModeFlag = "target-tls-mode"
targetTLSModeKey = "targetTLSMode"
targetIPv6Flag = "target-ipv6"
targetIPv6Key = "targetIPv6"
asyncFlag = "async"
asyncKey = "async"
sourceTLSConfigFlag = "source-tlsconfig"
Expand All @@ -133,6 +143,8 @@ const (
excludePatternKey = "excludePattern"
targetNamespaceFlag = "target-namespace"
targetNamespaceKey = "targetNamespace"
transactionIDFlag = "transaction-id"
transactionIDKey = "transactionID"
)

// flags to viper key map
Expand Down Expand Up @@ -164,12 +176,18 @@ var flagKeyMap = map[string]string{
targetHostsFlag: targetHostsKey,
targetUserNameFlag: targetUserNameKey,
targetPasswordFileFlag: targetPasswordFileKey,
targetKeyFileFlag: targetKeyFileKey,
targetCertFileFlag: targetCertFileKey,
targetCaCertFileFlag: targetCaCertFileKey,
targetTLSModeFlag: targetTLSModeKey,
targetIPv6Flag: targetIPv6Key,
asyncFlag: asyncKey,
sourceTLSConfigFlag: sourceTLSConfigKey,
tableOrSchemaNameFlag: tableOrSchemaNameKey,
includePatternFlag: includePatternKey,
excludePatternFlag: excludePatternKey,
targetNamespaceFlag: targetNamespaceKey,
transactionIDFlag: transactionIDKey,
}

// target database flags to viper key map
Expand All @@ -178,6 +196,11 @@ var targetFlagKeyMap = map[string]string{
targetHostsFlag: targetHostsKey,
targetUserNameFlag: targetUserNameKey,
targetPasswordFileFlag: targetPasswordFileKey,
targetKeyFileFlag: targetKeyFileKey,
targetCertFileFlag: targetCertFileKey,
targetCaCertFileFlag: targetCaCertFileKey,
targetTLSModeFlag: targetTLSModeKey,
targetIPv6Flag: targetIPv6Key,
}

// map of viper keys to environment variables
Expand All @@ -199,6 +222,7 @@ const (
configShowSubCmd = "show"
replicationSubCmd = "replication"
startReplicationSubCmd = "start"
replicationStatusSubCmd = "status"
listAllNodesSubCmd = "list_all_nodes"
startDBSubCmd = "start_db"
dropDBSubCmd = "drop_db"
Expand Down Expand Up @@ -239,6 +263,11 @@ type cmdGlobals struct {
targetDB string
targetUserName string
connFile string
targetKeyFile string
targetCertFile string
targetCaCertFile string
targetTLSMode string
targetIPv6 bool
}

var (
Expand Down Expand Up @@ -360,6 +389,18 @@ func setTargetDBOptionsUsingViper(flag string) error {
globals.targetUserName = viper.GetString(targetUserNameKey)
case targetPasswordFileFlag:
globals.targetPasswordFile = viper.GetString(targetPasswordFileKey)
case targetKeyFileFlag:
globals.targetKeyFile = viper.GetString(targetKeyFileKey)
case targetCertFileFlag:
globals.targetCertFile = viper.GetString(targetCertFileKey)
case targetCaCertFileFlag:
globals.targetCaCertFile = viper.GetString(targetCaCertFileKey)
case targetTLSModeFlag:
globals.targetTLSMode = viper.GetString(targetTLSModeKey)
case targetIPv6Flag:
globals.targetIPv6 = viper.GetBool(targetIPv6Key)
case verboseFlag:
globals.verbose = viper.GetBool(verboseKey)
default:
return fmt.Errorf("cannot find the relevant target database option for flag %q", flag)
}
Expand All @@ -373,7 +414,7 @@ func configViper(cmd *cobra.Command, flagsInConfig []string) error {
initConfig()

// target-flags are only available for replication start command
if cmd.CalledAs() == startReplicationSubCmd {
if cmd.CalledAs() == startReplicationSubCmd || cmd.CalledAs() == replicationStatusSubCmd {
for targetFlag := range targetFlagKeyMap {
flagsInConfig = append(flagsInConfig, targetFlag)
}
Expand Down Expand Up @@ -441,7 +482,7 @@ func loadConfig(cmd *cobra.Command) (err error) {

// load target db options from connection file to viper
// conn file is only available for replication subcommand
if cmd.CalledAs() == startReplicationSubCmd {
if cmd.CalledAs() == startReplicationSubCmd || cmd.CalledAs() == replicationStatusSubCmd {
err := loadConnToViper()
if err != nil {
return err
Expand Down Expand Up @@ -582,6 +623,7 @@ func constructCmds() []*cobra.Command {
makeCmdScrutinize(),
makeCmdManageConfig(),
makeCmdReplication(),
makeCmdGetReplicationStatus(),
makeCmdCreateConnection(),
// hidden cmds (for internal testing only)
makeCmdGetDrainingStatus(),
Expand Down
145 changes: 136 additions & 9 deletions commands/cmd_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,37 @@ func (c *CmdBase) ValidateParseBaseOptions(opt *vclusterops.DatabaseOptions) err

// parse TLS mode. vclusterops allows different behavior for NMA and HTTPS conns, but
// for simplicity and lack of use case outside k8s, vcluster does not.
if globals.tlsMode != "" {
switch tlsMode := strings.ToLower(globals.tlsMode); tlsMode {
err := validateParseTLSMode(opt, globals.tlsMode)
if err != nil {
return err
}

return nil
}

// ValidateParseBaseTargetOptions will validate and parse the required target options in each command
func (c *CmdBase) ValidateParseBaseTargetOptions(opt *vclusterops.DatabaseOptions) error {
// parse raw hosts
if len(opt.Hosts) > 0 {
err := util.ParseHostList(&opt.Hosts)
if err != nil {
return err
}
}

// parse TLS mode. vclusterops allows different behavior for NMA and HTTPS conns, but
// for simplicity and lack of use case outside k8s, vcluster does not.
err := validateParseTLSMode(opt, globals.targetTLSMode)
if err != nil {
return err
}

return nil
}

func validateParseTLSMode(opt *vclusterops.DatabaseOptions, tlsMode string) error {
if tlsMode != "" {
switch tlsModeLower := strings.ToLower(tlsMode); tlsModeLower {
case tlsModeEnable:
opt.DoVerifyHTTPSServerCert = false
opt.DoVerifyNMAServerCert = false
Expand All @@ -87,7 +116,7 @@ func (c *CmdBase) ValidateParseBaseOptions(opt *vclusterops.DatabaseOptions) err
opt.DoVerifyPeerCertHostname = true
default:
return fmt.Errorf("unrecognized TLS mode: %s. Allowed values are: '%s', '%s'",
globals.tlsMode, tlsModeEnable, tlsModeVerifyCA)
tlsMode, tlsModeEnable, tlsModeVerifyCA)
}
}

Expand Down Expand Up @@ -132,6 +161,10 @@ func (c *CmdBase) setCommonFlags(cmd *cobra.Command, flags []string) {
c.setTLSFlags(cmd)
}

if cmd.Name() == startReplicationSubCmd || cmd.Name() == replicationStatusSubCmd {
c.setTargetDBFlags(cmd)
}

if util.StringInArray(outputFileFlag, flags) {
cmd.Flags().StringVarP(
&c.output,
Expand Down Expand Up @@ -282,6 +315,79 @@ func (c *CmdBase) setTLSFlags(cmd *cobra.Command) {
)
}

func (c *CmdBase) setTargetDBFlags(cmd *cobra.Command) {
cmd.Flags().StringSliceVar(
&globals.targetHosts,
targetHostsFlag,
[]string{},
"A comma-separated list of hosts in target database.",
)
cmd.Flags().StringVar(
&globals.targetUserName,
targetUserNameFlag,
"",
"The name of a user in the target database.",
)
cmd.Flags().StringVar(
&globals.targetPasswordFile,
targetPasswordFileFlag,
"",
"The absolute path to a file containing the password for the target database. ",
)
cmd.Flags().StringVar(
&globals.connFile,
targetConnFlag,
"",
"[Required] The absolute path to the connection file created with the create_connection command, "+
"containing the database name, hosts, and password (if any) for the target database. "+
"Alternatively, you can provide this information manually with --target-db-name, "+
"--target-hosts, and --target-password-file",
)
markFlagsFileName(cmd, map[string][]string{targetConnFlag: {"yaml"}})

cmd.Flags().StringVar(
&globals.targetKeyFile,
targetKeyFileFlag,
"",
fmt.Sprintf("Path to the key file for the target database, the default value is %s",
filepath.Join(vclusterops.CertPathBase, "{username}.key")),
)
markFlagsFileName(cmd, map[string][]string{targetKeyFileFlag: {"key"}})

cmd.Flags().StringVar(
&globals.targetCertFile,
targetCertFileFlag,
"",
fmt.Sprintf("Path to the cert file for the target database, the default value is %s",
filepath.Join(vclusterops.CertPathBase, "{username}.pem")),
)
markFlagsFileName(cmd, map[string][]string{targetCertFileFlag: {"pem", "crt"}})
cmd.MarkFlagsRequiredTogether(targetKeyFileFlag, targetCertFileFlag)

cmd.Flags().StringVar(
&globals.targetCaCertFile,
targetCaCertFileFlag,
"",
fmt.Sprintf("Path to the trusted CA cert file for the target database, the default value is %s",
filepath.Join(vclusterops.CertPathBase, "rootca.pem")),
)
markFlagsFileName(cmd, map[string][]string{caCertFileFlag: {"pem", "crt"}})

cmd.Flags().StringVar(
&globals.targetTLSMode,
targetTLSModeFlag,
"",
fmt.Sprintf("Mode for TLS validation for the target database. "+
"Allowed values '%s', '%s', and '%s'. Default value is '%s'.",
tlsModeEnable, tlsModeVerifyCA, tlsModeVerifyFull, tlsModeEnable),
)
cmd.Flags().BoolVar(
&globals.targetIPv6,
targetIPv6Flag,
false,
"Whether the target hosts use IPv6 addresses. Hostnames resolve to IPv4 by default.")
}

func (c *CmdBase) initConfigParam() error {
// We need to find the path to the config param. The order of precedence is as follows:
// 1. Option
Expand Down Expand Up @@ -519,23 +625,44 @@ func (c *CmdBase) initCmdOutputFile() (*os.File, error) {

// getCertFilesFromPaths will update cert and key file from cert path options
func (c *CmdBase) getCertFilesFromCertPaths(opt *vclusterops.DatabaseOptions) error {
err := getCertFilesFromCertPaths(opt, globals.certFile, globals.keyFile, globals.caCertFile)
if err != nil {
return err
}

return nil
}

// getTargetCertFilesFromPaths will update target cert and key file from cert path options
func (c *CmdBase) getTargetCertFilesFromCertPaths(opt *vclusterops.DatabaseOptions) error {
err := getCertFilesFromCertPaths(opt, globals.targetCertFile, globals.targetKeyFile, globals.targetCaCertFile)
if err != nil {
return err
}

return nil
}

// getCertFilesFromPaths will update cert and key file from cert path options
func getCertFilesFromCertPaths(opt *vclusterops.DatabaseOptions,
certFile string, keyFile string, caCertFile string) error {
// TODO don't make this conditional on not using a PW for auth (see callers)
if globals.certFile != "" {
certData, err := os.ReadFile(globals.certFile)
if certFile != "" {
certData, err := os.ReadFile(certFile)
if err != nil {
return fmt.Errorf("failed to read certificate file: %w", err)
}
opt.Cert = string(certData)
}
if globals.keyFile != "" {
keyData, err := os.ReadFile(globals.keyFile)
if keyFile != "" {
keyData, err := os.ReadFile(keyFile)
if err != nil {
return fmt.Errorf("failed to read private key file: %w", err)
}
opt.Key = string(keyData)
}
if globals.caCertFile != "" {
caCertData, err := os.ReadFile(globals.caCertFile)
if caCertFile != "" {
caCertData, err := os.ReadFile(caCertFile)
if err != nil {
return fmt.Errorf("failed to read trusted CA certificate file: %w", err)
}
Expand Down
Loading

0 comments on commit ef6bed4

Please sign in to comment.