diff --git a/local-libs/vcluster/commands/cluster_command_launcher.go b/local-libs/vcluster/commands/cluster_command_launcher.go index fbc434493..b46c3d295 100644 --- a/local-libs/vcluster/commands/cluster_command_launcher.go +++ b/local-libs/vcluster/commands/cluster_command_launcher.go @@ -113,8 +113,6 @@ const ( ) // Flag and key for database replication -// -//nolint:dupl const ( targetDBNameFlag = "target-db-name" targetDBNameKey = "targetDBName" @@ -217,14 +215,12 @@ var keyEnvVarMap = map[string]string{ tlsModeKey: vclusterTLSModeEnv, } -//nolint:dupl const ( createDBSubCmd = "create_db" stopDBSubCmd = "stop_db" reviveDBSubCmd = "revive_db" manageConfigSubCmd = "manage_config" - connectionCmd = "connection" - createConnectionSubCmd = "create" + createConnectionSubCmd = "create_connection" configRecoverSubCmd = "recover" configShowSubCmd = "show" replicationSubCmd = "replication" @@ -253,7 +249,6 @@ const ( saveRestorePointsSubCmd = "save_restore_point" getDrainingStatusSubCmd = "get_draining_status" upgradeLicenseCmd = "upgrade_license" - checkConnectionSubCmd = "check" ) // cmdGlobals holds global variables shared by multiple @@ -491,7 +486,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 || cmd.CalledAs() == replicationStatusSubCmd || cmd.CalledAs() == checkConnectionSubCmd { + if cmd.CalledAs() == startReplicationSubCmd || cmd.CalledAs() == replicationStatusSubCmd { err := loadConnToViper() if err != nil { return err @@ -633,7 +628,7 @@ func constructCmds() []*cobra.Command { makeCmdManageConfig(), makeCmdReplication(), makeCmdGetReplicationStatus(), - makeCmdConnection(), + makeCmdCreateConnection(), // hidden cmds (for internal testing only) makeCmdGetDrainingStatus(), makeCmdPromoteSandbox(), diff --git a/local-libs/vcluster/commands/cmd_check_connection.go b/local-libs/vcluster/commands/cmd_check_connection.go deleted file mode 100644 index 4f5f28838..000000000 --- a/local-libs/vcluster/commands/cmd_check_connection.go +++ /dev/null @@ -1,158 +0,0 @@ -/* - (c) Copyright [2023-2024] Open Text. - 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 commands - -import ( - "fmt" - "strings" - - "github.com/spf13/cobra" - "github.com/vertica/vcluster/vclusterops" - "github.com/vertica/vcluster/vclusterops/util" - "github.com/vertica/vcluster/vclusterops/vlog" -) - -/* CmdCheckConnection - * - * Implements ClusterCommand interface - */ -type CmdCheckConnection struct { - connectionOptions *vclusterops.DatabaseOptions - CmdBase -} - -func makeCheckConnectionCmd() *cobra.Command { - newCmd := &CmdCheckConnection{} - opt := vclusterops.DatabaseOptionsFactory() - newCmd.connectionOptions = &opt - opt.Password = new(string) - cmd := makeBasicCobraCmd( - newCmd, - checkConnectionSubCmd, - "Validate a connection file", - `Check if a connection file is a valid one. - -Examples: - # Check a connection file - vcluster connection check --conn /opt/vertica/config/target_connection.yaml -`, - []string{connFlag}, - ) - - // local flags - newCmd.setLocalFlags(cmd) - markFlagsRequired(cmd, connFlag) - return cmd -} - -// setLocalFlags will set the local flags the command has -func (c *CmdCheckConnection) setLocalFlags(cmd *cobra.Command) { - cmd.Flags().StringVar( - &globals.connFile, - connFlag, - "", - "The absolute path to the connection file in yaml format.") -} - -func (c *CmdCheckConnection) Parse(inputArgv []string, logger vlog.Printer) error { - c.argv = inputArgv - logger.LogMaskedArgParse(c.argv) - logger.Info("Called Parse()") - connFile := globals.connFile - err := validateYamlFilePath(connFile, logger) - if err != nil { - return err - } - err = c.loadFromViper() - if err != nil { - return err - } - err = c.parseTargetHostList() - if err != nil { - return err - } - return c.ValidateParseBaseOptions(c.connectionOptions) -} - -func (c *CmdCheckConnection) parseTargetHostList() error { - if len(c.connectionOptions.Hosts) > 0 { - err := util.ParseHostList(&c.connectionOptions.Hosts) - if err != nil { - return fmt.Errorf("you must specify at least one target host to replicate to") - } - } - return nil -} - -func (c *CmdCheckConnection) Run(vcc vclusterops.ClusterCommands) error { - vcc.LogInfo("Called method Run()") - invalidHosts, err := c.verifyAndUpdateConnectionOptions(vcc) - if err != nil { - vcc.DisplayError(converErrorMessage(err, vcc.GetLog())) - return nil - } - if len(invalidHosts) > 0 { - vcc.DisplayWarning(hostWarningMsgOne + strings.Join(invalidHosts, ",")) - } - vcc.DisplayInfo("Successfully verified connection file") - return nil -} - -func (c *CmdCheckConnection) verifyAndUpdateConnectionOptions(vcc vclusterops.ClusterCommands) ([]string, error) { - fetchNodeDetailsOptions := vclusterops.VFetchNodesDetailsOptionsFactory() - password, err := c.passwordFileHelper(c.passwordFile) - if err != nil { - return nil, err - } - fetchNodeDetailsOptions.DatabaseOptions = *c.connectionOptions - fetchNodeDetailsOptions.LogPath = c.connectionOptions.LogPath - fetchNodeDetailsOptions.DatabaseOptions.Password = &password - validHosts, invalidHosts, returnErr := fetchNodeDetails(vcc, &fetchNodeDetailsOptions) - if len(validHosts) > 0 { - c.connectionOptions.Hosts = validHosts - return invalidHosts, nil - } - return invalidHosts, returnErr -} - -func (c *CmdCheckConnection) loadFromViper() error { - err := setTargetDBOptionsUsingViper(targetDBNameFlag) - if err != nil { - return err - } - c.connectionOptions.DBName = globals.targetDB - err = setTargetDBOptionsUsingViper(targetUserNameFlag) - if err != nil { - return err - } - c.connectionOptions.UserName = globals.targetUserName - err = setTargetDBOptionsUsingViper(targetPasswordFileFlag) - if err != nil { - return err - } - c.passwordFile = globals.targetPasswordFile - err = setTargetDBOptionsUsingViper(targetHostsFlag) - if err != nil { - return err - } - c.connectionOptions.RawHosts = globals.targetHosts - return nil -} - -// SetDatabaseOptions will assign a vclusterops.DatabaseOptions instance -func (c *CmdCheckConnection) SetDatabaseOptions(opt *vclusterops.DatabaseOptions) { - c.connectionOptions.LogPath = opt.LogPath -} diff --git a/local-libs/vcluster/commands/cmd_connection.go b/local-libs/vcluster/commands/cmd_connection.go deleted file mode 100644 index 39d0e5a3c..000000000 --- a/local-libs/vcluster/commands/cmd_connection.go +++ /dev/null @@ -1,38 +0,0 @@ -/* - (c) Copyright [2023-2024] Open Text. - 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 commands - -import ( - "github.com/spf13/cobra" -) - -/* CmdManageConfig - * - * A subcommand managing the YAML config file - * in the default or a specified directory. - * - * Implements ClusterCommand interface - */ - -func makeCmdConnection() *cobra.Command { - cmd := makeSimpleCobraCmd( - connectionCmd, - "Create and check connection file.", - `Create and check connection file.`) - cmd.AddCommand(makeCmdCreateConnection()) - cmd.AddCommand(makeCheckConnectionCmd()) - return cmd -} diff --git a/local-libs/vcluster/commands/cmd_create_connection.go b/local-libs/vcluster/commands/cmd_create_connection.go index ea711ee26..f7f07a0d1 100644 --- a/local-libs/vcluster/commands/cmd_create_connection.go +++ b/local-libs/vcluster/commands/cmd_create_connection.go @@ -16,8 +16,9 @@ package commands import ( + "errors" "fmt" - "strings" + "path/filepath" "github.com/spf13/cobra" "github.com/vertica/vcluster/vclusterops" @@ -25,10 +26,8 @@ import ( ) const ( - dotYaml = ".yaml" - dotYml = ".yml" - hostWarningMsgOne = "some hosts are invalid: " - hostWarningMsgTwo = "We removed those invalid hosts from the connection file." + dotYaml = ".yaml" + dotYml = ".yml" ) /* CmdCreateConnection @@ -36,16 +35,15 @@ const ( * Implements ClusterCommand interface */ type CmdCreateConnection struct { - checkConnection bool - connectionOptions *vclusterops.DatabaseOptions + connectionOptions *vclusterops.VReplicationDatabaseOptions CmdBase } func makeCmdCreateConnection() *cobra.Command { newCmd := &CmdCreateConnection{} - options := vclusterops.DatabaseOptionsFactory() - newCmd.connectionOptions = &options - newCmd.connectionOptions.Password = new(string) + opt := vclusterops.VReplicationDatabaseFactory() + newCmd.connectionOptions = &opt + opt.TargetDB.Password = new(string) cmd := makeBasicCobraCmd( newCmd, @@ -56,7 +54,7 @@ The generated connection file should be used with the replication command. Examples: # create the connection file to /tmp/vertica_connection.yaml - vcluster connection create --db-name platform_test_db --hosts 10.20.30.43 --db-user \ + vcluster create_connection --db-name platform_test_db --hosts 10.20.30.43 --db-user \ dkr_dbadmin --password-file /tmp/password.txt --conn /tmp/vertica_connection.yaml `, []string{connFlag}, @@ -64,32 +62,33 @@ Examples: // local flags newCmd.setLocalFlags(cmd) - cmd.AddCommand(makeCheckConnectionCmd()) - markFlagsRequired(cmd, dbNameFlag, hostsFlag, passwordFileFlag, connFlag) + + markFlagsRequired(cmd, dbNameFlag, hostsFlag, connFlag) return cmd } // setLocalFlags will set the local flags the command has func (c *CmdCreateConnection) setLocalFlags(cmd *cobra.Command) { cmd.Flags().StringVar( - &c.connectionOptions.DBName, + &c.connectionOptions.TargetDB.DBName, dbNameFlag, "", "The name of the database. You should only use this option if you want to override the database name in your configuration file.", ) cmd.Flags().StringSliceVar( - &c.connectionOptions.RawHosts, + &c.connectionOptions.TargetDB.Hosts, hostsFlag, []string{}, "A comma-separated list of hosts in database.") cmd.Flags().StringVar( - &c.connectionOptions.UserName, + &c.connectionOptions.TargetDB.UserName, dbUserFlag, "", "The name of the user in the target database.", ) + // password flags cmd.Flags().StringVar( - &c.passwordFile, + c.connectionOptions.TargetDB.Password, passwordFileFlag, "", "The absolute path to a file containing the password to the target database.", @@ -99,95 +98,44 @@ func (c *CmdCreateConnection) setLocalFlags(cmd *cobra.Command) { connFlag, "", "The absolute path to the connection file in yaml format.") - cmd.Flags().BoolVar( - &c.checkConnection, - "check-connection", - false, - "validate user inputs before creating the connection file", - ) markFlagsFileName(cmd, map[string][]string{connFlag: {"yaml"}}) } func (c *CmdCreateConnection) Parse(inputArgv []string, logger vlog.Printer) error { c.argv = inputArgv logger.LogMaskedArgParse(c.argv) - err := c.setDBPassword(c.connectionOptions) - if err != nil { - return err - } - err = c.validateParse(logger) - return err + return c.validateParse(logger) } func (c *CmdCreateConnection) validateParse(logger vlog.Printer) error { - connFile := globals.connFile - err := validateYamlFilePath(connFile, logger) - if err != nil { - return err + if !filepath.IsAbs(globals.connFile) { + filePathError := errors.New( + "Invalid connection file path: " + globals.connFile + ". The connection file path must be absolute.") + logger.Error(filePathError, "Connection file path error:") + return filePathError } - return c.ValidateParseBaseOptions(c.connectionOptions) + ext := filepath.Ext(globals.connFile) + if ext != dotYaml && ext != dotYml { + fileTypeError := errors.New("Invalid file type: " + ext + ". Only .yaml or .yml is allowed.") + logger.Error(fileTypeError, "Connection file type error:") + return fileTypeError + } + return c.ValidateParseBaseOptions(&c.connectionOptions.DatabaseOptions) } func (c *CmdCreateConnection) Run(vcc vclusterops.ClusterCommands) error { vcc.LogInfo("Called method Run()") - if c.checkConnection { - invalidHosts, err := c.verifyAndUpdateConnectionOptions(vcc) - if err != nil { - vcc.DisplayError(converErrorMessage(err, vcc.GetLog())) - return nil - } - if len(invalidHosts) > 0 { - vcc.DisplayWarning(hostWarningMsgOne + strings.Join(invalidHosts, ",") + " " + hostWarningMsgTwo) - } - vcc.DisplayInfo("Successfully verified connection parameters") - } else { - c.connectionOptions.Hosts = c.connectionOptions.RawHosts - } + // write target db info to vcluster connection file - err := c.writeConn() + err := writeConn(c.connectionOptions) if err != nil { - vcc.DisplayError("failed to write the connection file: " + err.Error()) - return nil + return fmt.Errorf("failed to write the connection file: %w", err) } vcc.DisplayInfo("Successfully wrote the connection file in %s", globals.connFile) - return err + return nil } // SetDatabaseOptions will assign a vclusterops.DatabaseOptions instance func (c *CmdCreateConnection) SetDatabaseOptions(opt *vclusterops.DatabaseOptions) { - c.connectionOptions.LogPath = opt.LogPath -} - -func (c *CmdCreateConnection) verifyAndUpdateConnectionOptions(vcc vclusterops.ClusterCommands) ([]string, error) { - fetchNodeDetailsOptions := vclusterops.VFetchNodesDetailsOptionsFactory() - - fetchNodeDetailsOptions.DatabaseOptions = *c.connectionOptions - fetchNodeDetailsOptions.LogPath = c.connectionOptions.LogPath - validHosts, invalidHosts, returnErr := fetchNodeDetails(vcc, &fetchNodeDetailsOptions) - if len(validHosts) > 0 { - c.connectionOptions.Hosts = validHosts - return invalidHosts, nil - } - return invalidHosts, returnErr -} - -// writeConn will save instructions for connecting to a database into a connection file. -func (c *CmdCreateConnection) writeConn() error { - if globals.connFile == "" { - return fmt.Errorf("conn path is empty") - } - dbConn := c.readTargetDBToDBConn() - // write a connection file with the given target database info from create_connection - err := dbConn.write(globals.connFile) - return err -} - -// readTargetDBToDBConn converts target database to DatabaseConnection -func (c *CmdCreateConnection) readTargetDBToDBConn() DatabaseConnection { - targetDBconn := MakeTargetDatabaseConn() - targetDBconn.TargetDBName = c.connectionOptions.DBName - targetDBconn.TargetHosts = c.connectionOptions.Hosts - targetDBconn.TargetPasswordFile = c.passwordFile - targetDBconn.TargetDBUser = c.connectionOptions.UserName - return targetDBconn + c.connectionOptions.DatabaseOptions = *opt } diff --git a/local-libs/vcluster/commands/helpers.go b/local-libs/vcluster/commands/helpers.go index 1c1073071..a4f9d6353 100644 --- a/local-libs/vcluster/commands/helpers.go +++ b/local-libs/vcluster/commands/helpers.go @@ -15,15 +15,10 @@ limitations under the License. package commands import ( - "errors" "fmt" "io" "os" - "path/filepath" - "strings" - "github.com/vertica/vcluster/vclusterops" - "github.com/vertica/vcluster/vclusterops/vlog" "golang.org/x/term" ) @@ -54,54 +49,3 @@ func isK8sEnvironment() bool { port, portSet := os.LookupEnv(kubernetesPort) return portSet && port != "" } - -// this function validates that the connection file path is absolute and ends with yaml or yml -func validateYamlFilePath(connFile string, logger vlog.Printer) error { - if !filepath.IsAbs(connFile) { - filePathError := errors.New( - "Invalid connection file path: " + globals.connFile + ". The connection file path must be absolute.") - logger.Error(filePathError, "Connection file path error:") - return filePathError - } - ext := filepath.Ext(connFile) - if ext != dotYaml && ext != dotYml { - fileTypeError := errors.New("Invalid file type: " + ext + ". Only .yaml or .yml is allowed.") - logger.Error(fileTypeError, "Connection file type error:") - return fileTypeError - } - return nil -} - -// this function translates raw error messages into more user friendly error message -func converErrorMessage(err error, logger vlog.Printer) string { - errMsg := err.Error() - logger.Error(err, "error to be converted into err msg") - if strings.Contains(errMsg, "down database") { - return "failed to vertify connection parameters. please check your db name and host list" - } else if strings.Contains(errMsg, "Wrong password") { - return "failed to vertify connection parameters. please check your db username and password" - } else if strings.Contains(errMsg, "rather than database") { - return "failed to vertify connection parameters. please check your db name" - } else if strings.Contains(errMsg, "no such host") || strings.Contains(errMsg, "network is unreachable") || - strings.Contains(errMsg, "fail to send request") || strings.Contains(errMsg, "server misbehaving") || - strings.Contains(errMsg, "i/o timeout") { - return "failed to vertify connection parameters. please check your host list" - } - return "failed to vertify connection parameters: " + errMsg -} - -// this function calls ClusterCommand.FetchNodesDetails() for each input hosts and return both valid and invalid hosts -func fetchNodeDetails(vcc vclusterops.ClusterCommands, fetchNodeDetailsOptions *vclusterops.VFetchNodesDetailsOptions) (validHosts []string, - invalidHosts []string, returnErr error) { - for _, host := range fetchNodeDetailsOptions.DatabaseOptions.RawHosts { - fetchNodeDetailsOptions.DatabaseOptions.RawHosts = []string{host} - _, err := vcc.VFetchNodesDetails(fetchNodeDetailsOptions) - if err == nil { - validHosts = append(validHosts, host) - } else { - invalidHosts = append(invalidHosts, host) - returnErr = err - } - } - return validHosts, invalidHosts, returnErr -} diff --git a/local-libs/vcluster/commands/user_input_test.go b/local-libs/vcluster/commands/user_input_test.go index bc8ed0a5b..676176200 100644 --- a/local-libs/vcluster/commands/user_input_test.go +++ b/local-libs/vcluster/commands/user_input_test.go @@ -109,23 +109,13 @@ func TestAsyncReplicationErrorMessage(t *testing.T) { func TestCreateConnectionFileWrongFileType(t *testing.T) { // vertica_connection.txt will not be created and a unique name is not required var tempConnFilePath = filepath.Join(os.TempDir(), "vertica_connection.txt") - passwordfile, err := os.CreateTemp(os.TempDir(), "password") - defer os.Remove(passwordfile.Name()) - assert.NoError(t, err) - err = simulateVClusterCli("vcluster connection create --db-name test_db1 --conn " + tempConnFilePath + - " --hosts 192.168.1.101 --password-file " + passwordfile.Name()) + err := simulateVClusterCli("vcluster create_connection --db-name test_db1 --conn " + tempConnFilePath + " --hosts 192.168.1.101") assert.ErrorContains(t, err, `Invalid file type`) } func TestCreateConnectionFileAbsolutePathChecking(t *testing.T) { var relativeConnFilePath = "vertica_connection.yaml" - - var passwordfile, err = os.CreateTemp(os.TempDir(), "password") - defer os.Remove(passwordfile.Name()) - assert.NoError(t, err) - - err = simulateVClusterCli("vcluster connection create --db-name test_db2 --conn " + relativeConnFilePath + - " --hosts vnode2 --password-file " + passwordfile.Name()) + err := simulateVClusterCli("vcluster create_connection --db-name test_db2 --conn " + relativeConnFilePath + " --hosts vnode2") assert.ErrorContains(t, err, `Invalid connection file path`) } @@ -135,11 +125,8 @@ func TestCreateConnectionFileRightFileTypes(t *testing.T) { defer os.Remove(tempFile.Name()) } assert.NoError(t, err) - passwordfile, err := os.CreateTemp(os.TempDir(), "password") - defer os.Remove(passwordfile.Name()) - assert.NoError(t, err) - err = simulateVClusterCli("vcluster connection create --db-name test_db3 --conn " + tempFile.Name() + - " --hosts vnode3 --password-file " + passwordfile.Name()) + + err = simulateVClusterCli("vcluster create_connection --db-name test_db3 --conn " + tempFile.Name() + " --hosts vnode3") assert.NoError(t, err) tempFile, err = os.CreateTemp("", tmpFilePrefixPattern+ymlExt) @@ -147,8 +134,7 @@ func TestCreateConnectionFileRightFileTypes(t *testing.T) { defer os.Remove(tempFile.Name()) } assert.NoError(t, err) - err = simulateVClusterCli("vcluster connection create --db-name test_db4 --conn " + tempFile.Name() + - " --hosts vnode4 --password-file " + passwordfile.Name()) + err = simulateVClusterCli("vcluster create_connection --db-name test_db4 --conn " + tempFile.Name() + " --hosts vnode4") assert.NoError(t, err) } @@ -158,13 +144,10 @@ func TestCreateConnection(t *testing.T) { os.Remove(tempFile.Name()) // clean up before test starts dbName := "platform_test_db" hosts := "192.168.1.101" - passwordfile, err := os.CreateTemp(os.TempDir(), "password") - defer os.Remove(passwordfile.Name()) - assert.NoError(t, err) // vcluster create_connection should succeed - err = simulateVClusterCli("vcluster connection create --db-name " + dbName + " --hosts " + hosts + - " --conn " + tempFile.Name() + " --password-file " + passwordfile.Name()) + err = simulateVClusterCli("vcluster create_connection --db-name " + dbName + " --hosts " + hosts + + " --conn " + tempFile.Name()) defer os.Remove(tempFile.Name()) // It may be possible for the simulate to create the file and return an error assert.NoError(t, err) diff --git a/local-libs/vcluster/commands/vcluster_connection.go b/local-libs/vcluster/commands/vcluster_connection.go index 964ae4e92..ac546ae90 100644 --- a/local-libs/vcluster/commands/vcluster_connection.go +++ b/local-libs/vcluster/commands/vcluster_connection.go @@ -5,6 +5,7 @@ import ( "os" "github.com/spf13/viper" + "github.com/vertica/vcluster/vclusterops" "gopkg.in/yaml.v3" ) @@ -31,6 +32,33 @@ func loadConnToViper() error { return nil } +// writeConn will save instructions for connecting to a database into a connection file. +func writeConn(targetdb *vclusterops.VReplicationDatabaseOptions) error { + if globals.connFile == "" { + return fmt.Errorf("conn path is empty") + } + + dbConn := readTargetDBToDBConn(targetdb) + + // write a connection file with the given target database info from create_connection + err := dbConn.write(globals.connFile) + if err != nil { + return err + } + + return nil +} + +// readTargetDBToDBConn converts target database to DatabaseConnection +func readTargetDBToDBConn(cnn *vclusterops.VReplicationDatabaseOptions) DatabaseConnection { + targetDBconn := MakeTargetDatabaseConn() + targetDBconn.TargetDBName = cnn.TargetDB.DBName + targetDBconn.TargetHosts = cnn.TargetDB.Hosts + targetDBconn.TargetPasswordFile = *cnn.TargetDB.Password + targetDBconn.TargetDBUser = cnn.TargetDB.UserName + return targetDBconn +} + // write writes connection information to connFilePath. It returns // any write error encountered. The viper in-built write function cannot // work well (the order of keys cannot be customized) so we used yaml.Marshal() diff --git a/local-libs/vcluster/sync-to-github.sh b/local-libs/vcluster/sync-to-github.sh index bb7b49c1b..b2193fee4 100755 --- a/local-libs/vcluster/sync-to-github.sh +++ b/local-libs/vcluster/sync-to-github.sh @@ -23,6 +23,7 @@ set -o nounset SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" FORCE= SKIP_COMMIT= +IGNORE_ROOT_PATH_CHECK= DRY_RUN_OPT= source $SCRIPT_DIR/logging-utils.sh @@ -34,6 +35,7 @@ function usage() { echo " -f Force, even when there are uncommitted files." echo " -s Skip git commit at the destination. Just sync the files." echo " -d Dry run only. Don't change anything in the destination repo." + echo " -i Ignore destination root path check. This option allows syncing the source directory to a subdirectory within the destination repo." echo " -v Verbose output." echo echo "Positional Arguments:" @@ -43,13 +45,14 @@ function usage() { exit 1 } -while getopts "hfsdv" opt +while getopts "hfsidv" opt do case $opt in h) usage;; f) FORCE=1;; v) set -o xtrace;; s) SKIP_COMMIT=1;; + i) IGNORE_ROOT_PATH_CHECK=1;; d) DRY_RUN_OPT="--dry-run" SKIP_COMMIT=1 ;; @@ -76,7 +79,7 @@ then logError "Destination directory isn't a git repo" exit 1 fi -if [[ "$DEST_GITROOT" != "$DEST_DIR" ]] +if [[ "$DEST_GITROOT" != "$DEST_DIR" && -z "$IGNORE_ROOT_PATH_CHECK" ]] then logError "Destination directory isn't git's root directory" exit 1 @@ -102,6 +105,7 @@ logAndRunCommand "rsync $DRY_RUN_OPT --archive \ --verbose \ --delete \ --exclude .git \ + --exclude .github \ --exclude vendor \ --exclude bin \ --exclude coverage.out \ @@ -119,7 +123,7 @@ logInfo "Changing directory to $DEST_DIR" cd $DEST_DIR logAndRunCommand "git add --all ." -MSG_FILE=$(mktemp git-commit-msg-XXXXX) +MSG_FILE=$(mktemp git-commit-msg-XXXXXX) trap "rm $MSG_FILE" EXIT echo "Sync from server repo ($SERVER_GITREF)" > $MSG_FILE logAndRunCommand "git commit --file $MSG_FILE" diff --git a/local-libs/vcluster/vclusterops/vcluster_version.go b/local-libs/vcluster/vclusterops/vcluster_version.go index 523cc0b95..ec2c73f55 100644 --- a/local-libs/vcluster/vclusterops/vcluster_version.go +++ b/local-libs/vcluster/vclusterops/vcluster_version.go @@ -13,6 +13,7 @@ limitations under the License. */ +// test 17 package vclusterops import (