Skip to content

Commit b529ac2

Browse files
author
Kristian
authored
Merge pull request #18 from itsdalmo/refactor-object-verb
Refactor command
2 parents f98a906 + 1f9a31f commit b529ac2

File tree

8 files changed

+92
-62
lines changed

8 files changed

+92
-62
lines changed

README.md

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ which ssm-sh
4747
$ ssm-sh --help
4848

4949
Usage:
50-
ssm-sh [OPTIONS] <list | run | shell>
50+
ssm-sh [OPTIONS] <command>
51+
52+
Application Options:
53+
-v, --version Print the version and exit.
5154

5255
AWS Options:
5356
-p, --profile= AWS Profile to use. (If you are not using Vaulted).
@@ -57,31 +60,61 @@ Help Options:
5760
-h, --help Show this help message
5861

5962
Available commands:
60-
list List managed instances. (aliases: ls)
61-
run Run a command on the targeted instances.
62-
shell Start an interactive shell. (aliases: sh)
63+
describe Description a document from ssm.
64+
list List managed instances or documents. (aliases: ls)
65+
run Run a command or document on the targeted instances.
66+
shell Start an interactive shell. (aliases: sh)
6367
```
6468

65-
#### List usage
69+
#### List instances usage
6670

6771
```bash
68-
$ ssm-sh list --help
72+
$ ssm-sh list instances --help
6973

7074
...
71-
[list command options]
75+
[instances command options]
7276
-f, --filter= Filter the produced list by tag (key=value,..)
7377
-l, --limit= Limit the number of instances printed (default: 50)
7478
-o, --output= Path to a file where the list of instances will be written as JSON.
7579
```
7680

77-
#### Run/shell usage
81+
#### List documents usage
82+
```bash
83+
$ ssm-sh list documents --help
84+
85+
...
86+
[documents command options]
87+
-f, --filter= Filter the produced list by property (Name, Owner, DocumentType, PlatformTypes)
88+
-l, --limit= Limit the number of instances printed (default: 50)
89+
```
90+
91+
#### Run cmd/shell usage
92+
93+
```bash
94+
$ ssm-sh run cmd --help
95+
96+
...
97+
[cmd command options]
98+
-i, --timeout= Seconds to wait for command result before timing out. (default: 30)
99+
-t, --target= One or more instance ids to target
100+
--target-file= Path to a JSON file containing a list of targets.
101+
102+
SSM options:
103+
-x, --extend-output Extend truncated command outputs by fetching S3 objects containing full ones
104+
-b, --s3-bucket= S3 bucket in which S3 objects containing full command outputs are stored. Required when --extend-output is provided.
105+
-k, --s3-key-prefix= Key prefix of S3 objects containing full command outputs.
106+
```
107+
108+
#### Run document usage
78109

79110
```bash
80-
$ ssm-sh run --help
111+
$ ssm-sh run document --help
81112

82113
...
83-
[run command options]
114+
[document command options]
115+
-n, --name= Name of document in ssm.
84116
-i, --timeout= Seconds to wait for command result before timing out. (default: 30)
117+
-p, --parameter= Zero or more parameters for the document (name:value)
85118
-t, --target= One or more instance ids to target
86119
--target-file= Path to a JSON file containing a list of targets.
87120

@@ -94,7 +127,7 @@ $ ssm-sh run --help
94127
## Example
95128

96129
```bash
97-
$ vaulted -n lab-admin -- ssm-sh list --filter Name="*itsdalmo" -o example.json
130+
$ vaulted -n lab-admin -- ssm-sh list instances --filter Name="*itsdalmo" -o example.json
98131

99132
Instance ID | Name | State | Image ID | Platform | Version | IP | Status | Last pinged
100133
i-03762678c45546813 | ssm-manager-manual-test-itsdalmo | running | ami-db1688a2 | Amazon Linux | 2.0 | 172.53.17.163 | Online | 2018-02-09 12:37
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ import (
1010
"github.com/pkg/errors"
1111
)
1212

13-
type ListCommand struct {
13+
type ListInstancesCommand struct {
1414
Tags []*tag `short:"f" long:"filter" description:"Filter the produced list by tag (key=value,..)"`
1515
Limit int64 `short:"l" long:"limit" description:"Limit the number of instances printed" default:"50"`
1616
Output string `short:"o" long:"output" description:"Path to a file where the list of instances will be written as JSON."`
1717
}
1818

19-
func (command *ListCommand) Execute([]string) error {
19+
func (command *ListInstancesCommand) Execute([]string) error {
2020
sess, err := newSession()
2121
if err != nil {
2222
return errors.Wrap(err, "failed to create new session")

command/root.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,26 @@ package command
33
var Command RootCommand
44

55
type RootCommand struct {
6-
Version func() `short:"v" long:"version" description:"Print the version and exit."`
7-
List ListCommand `command:"list" alias:"ls" description:"List managed instances."`
8-
Shell ShellCommand `command:"shell" alias:"sh" description:"Start an interactive shell."`
9-
Run RunCommand `command:"run" description:"Run a command on the targeted instances."`
10-
ListDocuments ListDocumentsCommand `command:"list-documents" alias:"ld" description:"List available documents in ssm."`
11-
RunDocument RunDocumentCommand `command:"run-document" description:"Runs a document from ssm."`
12-
DescribeDocument DescribeDocumentCommand `command:"describe-document" description:"Description a document from ssm."`
13-
AwsOpts AwsOptions `group:"AWS Options"`
6+
Version func() `short:"v" long:"version" description:"Print the version and exit."`
7+
List ListCommand `command:"list" alias:"ls" description:"List managed instances or documents."`
8+
Shell ShellCommand `command:"shell" alias:"sh" description:"Start an interactive shell."`
9+
Run RunCommand `command:"run" description:"Run a command or document on the targeted instances."`
10+
Describe DescribeCommand `command:"describe" description:"Description a document from ssm."`
11+
AwsOpts AwsOptions `group:"AWS Options"`
12+
}
13+
14+
type ListCommand struct {
15+
Instances ListInstancesCommand `command:"instances" alias:"ins" description:"List managed instances."`
16+
Documents ListDocumentsCommand `command:"documents" alias:"doc" description:"List managed documents."`
17+
}
18+
19+
type RunCommand struct {
20+
RunCmd RunCmdCommand `command:"command" alias:"cmd" description:"Run a command on the targeted instances."`
21+
RunDocument RunDocumentCommand `command:"document" alias:"doc" description:"Runs a document from ssm."`
22+
}
23+
24+
type DescribeCommand struct {
25+
Describe DescribeDocumentCommand `command:"document" alias:"doc" description:"Description a document from ssm."`
1426
}
1527

1628
type AwsOptions struct {

command/run.go renamed to command/run-cmd.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import (
1111
"github.com/pkg/errors"
1212
)
1313

14-
type RunCommand struct {
14+
type RunCmdCommand struct {
1515
Timeout int `short:"i" long:"timeout" description:"Seconds to wait for command result before timing out." default:"30"`
1616
SSMOpts SSMOptions `group:"SSM options"`
1717
TargetOpts TargetOptions
1818
}
1919

20-
func (command *RunCommand) Execute(args []string) error {
20+
func (command *RunCmdCommand) Execute(args []string) error {
2121
sess, err := newSession()
2222
if err != nil {
2323
return errors.Wrap(err, "failed to create new aws session")
@@ -35,7 +35,8 @@ func (command *RunCommand) Execute(args []string) error {
3535
fmt.Printf("Use ctrl-c to abort the command early.\n\n")
3636

3737
// Start the command
38-
commandID, err := m.RunCommand(targets, strings.Join(args, " "))
38+
cmd := strings.Join(args, " ")
39+
commandID, err := m.RunCommand(targets, "AWS-RunShellScript", map[string]string{"commands": cmd})
3940
if err != nil {
4041
return errors.Wrap(err, "failed to run command")
4142
}

command/run-document.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type RunDocumentCommand struct {
1414
Name string `short:"n" long:"name" description:"Name of document in ssm."`
1515
Timeout int `short:"i" long:"timeout" description:"Seconds to wait for command result before timing out." default:"30"`
1616
Parameters map[string]string `short:"p" long:"parameter" description:"Zero or more parameters for the document (name:value)"`
17+
SSMOpts SSMOptions `group:"SSM options"`
1718
TargetOpts TargetOptions
1819
}
1920

@@ -28,15 +29,19 @@ func (command *RunDocumentCommand) Execute(args []string) error {
2829
return errors.Wrap(err, "failed to create new aws session")
2930
}
3031

31-
m := manager.NewManager(sess, Command.AwsOpts.Region, manager.Opts{})
32+
opts, err := command.SSMOpts.Parse()
33+
if err != nil {
34+
return err
35+
}
36+
m := manager.NewManager(sess, Command.AwsOpts.Region, *opts)
3237
targets, err := setTargets(command.TargetOpts)
3338
if err != nil {
3439
return errors.Wrap(err, "failed to set targets")
3540
}
3641
fmt.Printf("Use ctrl-c to abort the command early.\n\n")
3742

3843
// Start the command
39-
commandID, err := m.RunDocument(targets, command.Name, command.Parameters)
44+
commandID, err := m.RunCommand(targets, command.Name, command.Parameters)
4045
if err != nil {
4146
return errors.Wrap(err, "failed to run command")
4247
}

command/shell.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (command *ShellCommand) Execute([]string) error {
7171
}
7272

7373
// Start command
74-
commandID, err := m.RunCommand(targets, cmd)
74+
commandID, err := m.RunCommand(targets, "AWS-RunShellScript", map[string]string{"commands": cmd})
7575
if err != nil {
7676
return errors.Wrap(err, "failed to Run command")
7777
}

manager/manager.go

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -208,29 +208,7 @@ func (m *Manager) describeInstances(instances []*ssm.InstanceInformation, tagFil
208208
}
209209

210210
// RunCommand on the given instance ids.
211-
func (m *Manager) RunCommand(instanceIds []string, command string) (string, error) {
212-
input := &ssm.SendCommandInput{
213-
InstanceIds: aws.StringSlice(instanceIds),
214-
DocumentName: aws.String("AWS-RunShellScript"),
215-
Comment: aws.String("Interactive command."),
216-
Parameters: map[string][]*string{"commands": {aws.String(command)}},
217-
}
218-
if m.s3Bucket != "" {
219-
input.OutputS3BucketName = aws.String(m.s3Bucket)
220-
}
221-
if m.s3KeyPrefix != "" {
222-
input.OutputS3KeyPrefix = aws.String(m.s3KeyPrefix)
223-
}
224-
res, err := m.ssmClient.SendCommand(input)
225-
if err != nil {
226-
return "", err
227-
}
228-
229-
return aws.StringValue(res.Command.CommandId), nil
230-
}
231-
232-
// RunDocument on the given instance ids.
233-
func (m *Manager) RunDocument(instanceIds []string, name string, parameters map[string]string) (string, error) {
211+
func (m *Manager) RunCommand(instanceIds []string, name string, parameters map[string]string) (string, error) {
234212

235213
var params map[string][]*string
236214

@@ -247,7 +225,12 @@ func (m *Manager) RunDocument(instanceIds []string, name string, parameters map[
247225
Comment: aws.String("Document triggered through ssm-sh."),
248226
Parameters: params,
249227
}
250-
228+
if m.s3Bucket != "" {
229+
input.OutputS3BucketName = aws.String(m.s3Bucket)
230+
}
231+
if m.s3KeyPrefix != "" {
232+
input.OutputS3KeyPrefix = aws.String(m.s3KeyPrefix)
233+
}
251234
res, err := m.ssmClient.SendCommand(input)
252235
if err != nil {
253236
return "", err

manager/manager_test.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ func TestRunCommand(t *testing.T) {
383383

384384
t.Run("Run works", func(t *testing.T) {
385385
expected := "command-1"
386-
actual, err := m.RunCommand(targets, "ls -la")
386+
actual, err := m.RunCommand(targets, "AWS-RunShellScript", map[string]string{"commands": "ls -la"})
387387
assert.Nil(t, err)
388388
assert.NotNil(t, actual)
389389
assert.Equal(t, expected, actual)
@@ -395,17 +395,13 @@ func TestRunCommand(t *testing.T) {
395395
ssmMock.Error = false
396396
}()
397397

398-
actual, err := m.RunCommand(targets, "ls -la")
398+
actual, err := m.RunCommand(targets, "AWS-RunShellScript", map[string]string{"commands": "ls -la"})
399399
assert.NotNil(t, err)
400400
assert.EqualError(t, err, "expected")
401401
assert.Equal(t, "", actual)
402402
})
403403
}
404404

405-
/*
406-
func TestRunDocumentCommand(t *testing.T) {
407-
}*/
408-
409405
func TestAbortCommand(t *testing.T) {
410406
ssmMock := &manager.MockSSM{
411407
Error: false,
@@ -433,14 +429,14 @@ func TestAbortCommand(t *testing.T) {
433429
}
434430

435431
t.Run("Abort works", func(t *testing.T) {
436-
id, err := m.RunCommand(targets, "ls -la")
432+
id, err := m.RunCommand(targets, "AWS-RunShellScript", map[string]string{"commands": "ls -la"})
437433
assert.Nil(t, err)
438434
err = m.AbortCommand(targets, id)
439435
assert.Nil(t, err)
440436
})
441437

442438
t.Run("Invalid command id errors are propagated", func(t *testing.T) {
443-
_, err := m.RunCommand(targets, "ls -la")
439+
_, err := m.RunCommand(targets, "AWS-RunShellScript", map[string]string{"commands": "ls -la"})
444440
assert.Nil(t, err)
445441
err = m.AbortCommand(targets, "invalid")
446442
assert.NotNil(t, err)
@@ -486,7 +482,7 @@ func TestOutput(t *testing.T) {
486482
}
487483

488484
t.Run("Get output works with standard out", func(t *testing.T) {
489-
id, err := m.RunCommand(targets, "ls -la")
485+
id, err := m.RunCommand(targets, "AWS-RunShellScript", map[string]string{"commands": "ls -la"})
490486
assert.Nil(t, err)
491487

492488
ctx := context.Background()
@@ -510,7 +506,7 @@ func TestOutput(t *testing.T) {
510506
ssmMock.CommandStatus = "Success"
511507
}()
512508

513-
id, err := m.RunCommand(targets, "ls -la")
509+
id, err := m.RunCommand(targets, "AWS-RunShellScript", map[string]string{"commands": "ls -la"})
514510
assert.Nil(t, err)
515511

516512
ctx := context.Background()
@@ -525,7 +521,7 @@ func TestOutput(t *testing.T) {
525521
})
526522

527523
t.Run("Get output is aborted if the context is done", func(t *testing.T) {
528-
id, err := m.RunCommand(targets, "ls -la")
524+
id, err := m.RunCommand(targets, "AWS-RunShellScript", map[string]string{"commands": "ls -la"})
529525
assert.Nil(t, err)
530526

531527
ctx, cancel := context.WithCancel(context.Background())

0 commit comments

Comments
 (0)