Skip to content

Commit

Permalink
fix(ssh-args): parse escaped quotes correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
Jorres committed May 23, 2024
1 parent 6c0b55c commit 4fb2872
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 2 deletions.
2 changes: 1 addition & 1 deletion cmd/maintenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func NewMaintenanceCmd() *cobra.Command {
Use: "maintenance",
Short: "Request hosts from the Cluster Management System",
Long: `ydbops maintenance [command]:
Manage host maintenance operations: request and return nodes
Manage host maintenance operations: request and return hosts
with performed maintenance back to the cluster.`,
PreRunE: cli.PopulateProfileDefaultsAndValidate(
restartOpts, rootOpts,
Expand Down
33 changes: 33 additions & 0 deletions pkg/options/options_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package options

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestOptions(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Options Suite")
}

var _ = Describe("Test parsing SSHArgs", func() {
DescribeTable("SSH arguments parsing",
func(input string, expected []string) {
Expect(parseSSHArgs(input)).To(Equal(expected))
},
Entry("whitespace separated arguments",
"arg1 arg2 arg3",
[]string{"arg1", "arg2", "arg3"},
),
Entry("not split by whitespace inside quotes",
"arg1 arg2 ProxyCommand=\"cmd\"",
[]string{"arg1", "arg2", "ProxyCommand=\"cmd\""},
),
Entry("not split by comma",
"arg1,arg2 ProxyCommand=\"cmd\"",
[]string{"arg1,arg2", "ProxyCommand=\"cmd\""},
),
)
})
37 changes: 36 additions & 1 deletion pkg/options/restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strconv"
"strings"
"time"
"unicode"
"unicode/utf8"

"github.com/spf13/pflag"
Expand Down Expand Up @@ -66,6 +67,7 @@ type RestartOptions struct {
var (
startedUnparsedFlag string
versionUnparsedFlag string
rawSSHUnparsedArgs string
)

var RestartOptionsInstance = &RestartOptions{}
Expand Down Expand Up @@ -132,6 +134,8 @@ func (o *RestartOptions) Validate() error {
}
}

o.SSHArgs = parseSSHArgs(rawSSHUnparsedArgs)

_, errFromIds := o.GetNodeIds()
_, errFromFQDNs := o.GetNodeFQDNs()
if errFromIds != nil && errFromFQDNs != nil {
Expand All @@ -155,7 +159,7 @@ func (o *RestartOptions) DefineFlags(fs *pflag.FlagSet) {

fs.StringVar(&o.CustomSystemdUnitName, "systemd-unit", "", "Specify custom systemd unit name to restart")

fs.StringSliceVarP(&o.SSHArgs, "ssh-args", "", nil,
fs.StringVar(&rawSSHUnparsedArgs, "ssh-args", "",
`This argument will be used when ssh-ing to the nodes. It may be used to override
the ssh command itself, ssh username or any additional arguments.
E.g.:
Expand Down Expand Up @@ -256,3 +260,34 @@ func (o *RestartOptions) GetNodeIds() ([]uint32, error) {

return ids, nil
}

func parseSSHArgs(rawArgs string) []string {
args := []string{}
isInsideQuotes := false

rawRunes := []rune(rawArgs)
curArg := []rune{}
for i := 0; i < len(rawRunes); i++ {
if rawRunes[i] == '\\' && i+1 < len(rawRunes) && rawRunes[i+1] == '"' {
isInsideQuotes = !isInsideQuotes
i++
curArg = append(curArg, '"')
continue
}

if unicode.IsSpace(rawRunes[i]) {
if len(curArg) > 0 {
args = append(args, string(curArg))
}
curArg = []rune{}
} else {
curArg = append(curArg, rawRunes[i])
}
}

if len(curArg) > 0 {
args = append(args, string(curArg))
}

return args
}

0 comments on commit 4fb2872

Please sign in to comment.