rezept 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b1e46b66acf98930fd5070f065439fd87ea1418e
4
- data.tar.gz: 5145a5beb089d59c11980b4d007b58a67f8bc9ad
3
+ metadata.gz: a084f39244aeebaf00fd8d2307de6c7dd189a4e5
4
+ data.tar.gz: f6b24452efdbdf3798883f4be75515d6b57ee779
5
5
  SHA512:
6
- metadata.gz: c8df9983eed7551c6715fe1c2cf9215489636d609966a532523d0a1ff51f14dff8ed09c6f3e6b73e933087d341d08aef65a549c9049d6baf15890c170ad01870
7
- data.tar.gz: 12f87f8f44a03d21a7027988d221323c61ecea92c3bb252e4f19ba85caeccdfb6d2fedcf7b3266f3aea514c36f8b2839f62718e529e6d0c48eafa0c2e1287941
6
+ metadata.gz: ce615a416a985a938879af31ca0f6d6628c3b86f446a94bd5a0379066c6cad75506387b50ee54438a6f75b7a638515c6b6a40b80aa19ab549f24190fec4e570b
7
+ data.tar.gz: 796d1a2eab98ee9ca2bf847126a67b416f5f4ca778f3e4c1ba589083555f07c82cb055109cbceff53023a877f312828d05e6b8b112c672901984b4aeadfba116
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ ## 0.1.0
2
+
3
+ - Add `run_command` command [#1][]
4
+ - Some small fixes
5
+
6
+ ## 0.0.2
7
+
8
+ - Initial release
9
+
10
+ ## 0.0.1 (yunked)
11
+
12
+ <!--- The following link definition list is generated by PimpMyChangelog --->
13
+ [#1]: https://github.com/serverworks/rezept/issues/1
data/Docfile CHANGED
@@ -9,7 +9,8 @@ template "runShellScriptTemplate" do
9
9
  action "aws:runShellScript"
10
10
  name "runShellScript"
11
11
  inputs do
12
- commands __script(context.commands)
12
+ runCommand __script(context.commands)
13
+ TimeoutSeconds 10
13
14
  end
14
15
  end
15
16
  end
@@ -18,7 +19,7 @@ end
18
19
 
19
20
  Command "My-RunShellScript" do
20
21
  account_ids []
21
- include_template "runShellScriptTemplate", commands: "echo 1"
22
+ include_template "runShellScriptTemplate", commands: "echo 1 >> /tmp/result.txt"
22
23
  end
23
24
 
24
25
  Command "My-RunShellScript-2" do
@@ -31,29 +32,13 @@ Command "My-RunShellScript-2" do
31
32
  action "aws:runShellScript"
32
33
  name "runShellScript"
33
34
  inputs do
34
- commands __script(<<-'EOS')
35
+ runCommand __script(<<-'EOS')
35
36
  #! /bin/bash
36
- echo 1
37
- echo 2
38
- echo 3
37
+ echo 1 >> /tmp/results.txt
38
+ echo 2 >> /tmp/results.txt
39
+ exit 1
39
40
  EOS
40
- end
41
- end
42
- end
43
- end
44
- end
45
-
46
- Command "My-RunShellScript-3" do
47
- account_ids []
48
- content do
49
- __dsl do
50
- schemaVersion "2.0"
51
- description "Run a shell script"
52
- mainSteps do |*|
53
- action "aws:runShellScript"
54
- name "runShellScript"
55
- inputs do
56
- commands __script_file("script.sh")
41
+ TimeoutSeconds 10
57
42
  end
58
43
  end
59
44
  end
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Rezept
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/rezept.svg)](https://badge.fury.io/rb/rezept)
4
+
3
5
  A tool to manage EC2 Systems Manager (SSM) Documents with programmable DSL.
4
6
 
5
7
  ## Installation
@@ -101,6 +103,33 @@ Options:
101
103
  # Default: true
102
104
  ```
103
105
 
106
+ #### run_command
107
+ Run the commands
108
+
109
+ ```
110
+ $ rezept help run_command
111
+ Usage:
112
+ rezept run_command -n, --name=NAME
113
+
114
+ Options:
115
+ -n, --name=NAME # Name of the document
116
+ -i, [--instance-ids=one two three] # EC2 Instance IDs
117
+ -t, [--tags=key:value] # EC2 Instance tags
118
+ -p, [--parameters=key:value] # Parameters for the document
119
+ [--dry-run], [--no-dry-run] # Dry run (Only output the targets)
120
+ [--wait], [--no-wait] # Wait and check for all results
121
+ -f, [--file=FILE] # Configuration file
122
+ # Default: Docfile
123
+ [--color], [--no-color] # Disable colorize
124
+ # Default: true
125
+ [--amazon-docs], [--no-amazon-docs] # Include Amazon owned documents
126
+ [--dsl-content], [--no-dsl-content] # Convert JSON contents to DSL
127
+ # Default: true
128
+ ```
129
+
130
+ - If you specify multiple values to `tags` and `parameters`, separate them with commas(`,`).
131
+ - When you use the `wait` option, the exit code will be `0` if the commands succeed on the all instances, else it will be `1`.
132
+
104
133
  ## Advanced methods
105
134
 
106
135
  #### Script styled commands (__script)
@@ -118,7 +147,7 @@ Command "My-RunShellScript" do
118
147
  action "aws:runShellScript"
119
148
  name "runShellScript"
120
149
  inputs do
121
- commands __script(<<-'EOS')
150
+ runCommand __script(<<-'EOS')
122
151
  #! /bin/bash
123
152
  echo 1
124
153
  echo 2
@@ -145,7 +174,7 @@ Document Type: 'Command'
145
174
  "action": "aws:runShellScript",
146
175
  "name": "runShellScript",
147
176
  "inputs": {
148
- "commands": [
177
+ "runCommand": [
149
178
  "#! /bin/bash",
150
179
  "echo 1",
151
180
  "echo 2",
@@ -172,7 +201,7 @@ Command "My-RunShellScript" do
172
201
  action "aws:runShellScript"
173
202
  name "runShellScript"
174
203
  inputs do
175
- commands __script_file("script.sh")
204
+ runCommand __script_file("script.sh")
176
205
  end
177
206
  end
178
207
  end
@@ -203,7 +232,7 @@ Document Type: 'Command'
203
232
  "action": "aws:runShellScript",
204
233
  "name": "runShellScript",
205
234
  "inputs": {
206
- "commands": [
235
+ "runCommand": [
207
236
  "#! /bin/bash",
208
237
  "echo 1",
209
238
  "echo 2",
@@ -229,7 +258,7 @@ template "runShellScriptTemplate" do
229
258
  action "aws:runShellScript"
230
259
  name "runShellScript"
231
260
  inputs do
232
- commands __script(context.commands)
261
+ runCommand __script(context.commands)
233
262
  end
234
263
  end
235
264
  end
@@ -256,7 +285,7 @@ Document Type: 'Command'
256
285
  "action": "aws:runShellScript",
257
286
  "name": "runShellScript",
258
287
  "inputs": {
259
- "commands": [
288
+ "runCommand": [
260
289
  "echo 1"
261
290
  ]
262
291
  }
@@ -72,6 +72,85 @@ module Rezept
72
72
  _export_file(ret, options['output']) unless options['output'].nil?
73
73
  end
74
74
 
75
+ def run_command(options)
76
+ dry_run = options['dry_run'] ? '[Dry run] ' : ''
77
+
78
+ if options['instance_ids'].nil? and options['tags'].nil?
79
+ raise "Please specify the targets (--instance-ids/-i' or '--target-tags/-t')"
80
+ end
81
+
82
+ instances = @client.get_target_instances(
83
+ options['instance_ids'],
84
+ _tags_to_criteria(options['tags'], 'name')
85
+ )
86
+ info("#{dry_run}Target instances...")
87
+ instances.each do |instance|
88
+ name_tag = instance.tags.select {|i| i.key == 'Name'}
89
+ if name_tag.empty?
90
+ info("- #{instance.instance_id}")
91
+ else
92
+ info("- #{name_tag[0].value} (#{instance.instance_id})")
93
+ end
94
+ end
95
+
96
+ if dry_run.empty?
97
+ command = @client.run_command(
98
+ options['name'],
99
+ options['instance_ids'],
100
+ _tags_to_criteria(options['tags'], 'key'),
101
+ _convert_paraeters(options['parameters'])
102
+ )
103
+ _wait_all_results(command.command_id) if options['wait']
104
+ end
105
+ end
106
+
107
+ def _tags_to_criteria(targets, key_name)
108
+ return nil if targets.nil?
109
+ ret = []
110
+ targets.each {|k,v| ret << {key_name => "tag:#{k}", 'values' => v.split(',')} }
111
+ ret
112
+ end
113
+
114
+ def _convert_paraeters(parameters)
115
+ return nil if parameters.nil?
116
+ ret = {}
117
+ parameters.each do |k,v|
118
+ ret[k] = v.split(',')
119
+ end
120
+ ret
121
+ end
122
+
123
+ def _wait_all_results(command_id)
124
+ info("Wait for all results...")
125
+
126
+ done = false
127
+ failure = false
128
+ done_instances = []
129
+
130
+ until done do
131
+ sleep 1
132
+ invocations = @client.list_command_invocations(command_id)
133
+ invocations.each do |invocation|
134
+ break if done_instances.include?(invocation.instance_id)
135
+ unless ['Pending', 'InProgress'].include?(invocation.status)
136
+ case invocation.status
137
+ when 'Success'
138
+ info("- #{invocation.instance_id} => #{invocation.status}")
139
+ when 'Delayed'
140
+ warn("- #{invocation.instance_id} => #{invocation.status}")
141
+ else
142
+ fatal("- #{invocation.instance_id} => #{invocation.status}")
143
+ failure = true
144
+ end
145
+ done_instances << invocation.instance_id
146
+ done = true if done_instances.length == invocations.length
147
+ end
148
+ end
149
+ end
150
+
151
+ exit(1) if failure
152
+ end
153
+
75
154
  def _apply_docs(local, remote, dry_run)
76
155
  local.each do |l|
77
156
  l_ids = l.delete('account_ids')
data/lib/rezept/cli.rb CHANGED
@@ -29,12 +29,23 @@ module Rezept
29
29
  end
30
30
 
31
31
  desc "convert", "Convert the documents to the other format"
32
- option :name, aliases: '-n', desc: 'Name of document', type: :string, required: true
33
- option :type, aliases: '-t', desc: 'Type of document (Command|Automation)', type: :string, required: true
32
+ option :name, aliases: '-n', desc: 'Name of the document', type: :string, required: true
33
+ option :type, aliases: '-t', desc: 'Type of the document (Command|Automation)', type: :string, required: true
34
34
  option :format, desc: 'Output format (json|ruby)', type: :string
35
35
  option :output, aliases: '-o', desc: 'Output filename (path)', type: :string
36
36
  def convert
37
37
  @actions.convert(options)
38
38
  end
39
+
40
+ desc "run_command", "Run the commands"
41
+ option :name, aliases: '-n', desc: 'Name of the document', type: :string, required: true
42
+ option :instance_ids, aliases: '-i', desc: 'EC2 Instance IDs', type: :array
43
+ option :tags, aliases: '-t', desc: 'EC2 Instance tags', type: :hash
44
+ option :parameters, aliases: '-p', desc: 'Parameters for the document', type: :hash
45
+ option :dry_run, desc: 'Dry run (Only output the targets)', type: :boolean, default: false
46
+ option :wait, desc: 'Wait and check for all results', type: :boolean, default: false
47
+ def run_command
48
+ @actions.run_command(options)
49
+ end
39
50
  end
40
51
  end
data/lib/rezept/client.rb CHANGED
@@ -5,6 +5,7 @@ module Rezept
5
5
 
6
6
  def initialize
7
7
  @ssm = Aws::SSM::Client.new
8
+ @ec2 = Aws::EC2::Client.new
8
9
  end
9
10
 
10
11
  def set_options(options)
@@ -57,7 +58,40 @@ module Rezept
57
58
  name: doc['name'],
58
59
  permission_type: 'Share',
59
60
  account_ids_to_add: add_ids,
60
- account_ids_to_remove: rm_ids)
61
+ account_ids_to_remove: rm_ids
62
+ )
63
+ end
64
+
65
+ def get_target_instances(instance_ids, filters, next_token=nil)
66
+ instances = []
67
+
68
+ ret = @ec2.describe_instances(
69
+ instance_ids: instance_ids,
70
+ filters: filters,
71
+ next_token: next_token
72
+ )
73
+ ret.reservations.each do |reservation|
74
+ instances.concat(reservation.instances)
75
+ end
76
+
77
+ instances.concat(get_target_instances(instance_ids, filters, ret.next_token)) unless ret.next_token.nil?
78
+ instances
79
+ end
80
+
81
+ def run_command(name, instance_ids, targets, parameters)
82
+ @ssm.send_command(
83
+ document_name: name,
84
+ instance_ids: instance_ids,
85
+ targets: targets,
86
+ parameters: parameters
87
+ ).command
88
+ end
89
+
90
+ def list_command_invocations(command_id, next_token=nil)
91
+ ret = @ssm.list_command_invocations(command_id: command_id)
92
+ invocations = ret.command_invocations
93
+ invocations.concat(list_command_invocations(command_id, ret.next_token)) unless ret.next_token.nil?
94
+ invocations
61
95
  end
62
96
 
63
97
  end
data/lib/rezept/logger.rb CHANGED
@@ -53,8 +53,8 @@ module Rezept
53
53
  super { Rezept::TermColor.red(msg) }
54
54
  end
55
55
 
56
- def error(progname = nil, method_name = nil, msg, backtrace)
57
- super(progname) { { method_name: method_name, message: msg, backtrace: backtrace } }
56
+ def error(msg)
57
+ super { Rezept::TermColor.red(msg) }
58
58
  end
59
59
 
60
60
  module Helper
@@ -1,3 +1,3 @@
1
1
  module Rezept
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rezept
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Serverworks Co.,Ltd.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-15 00:00:00.000000000 Z
11
+ date: 2017-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -148,6 +148,7 @@ files:
148
148
  - ".gitignore"
149
149
  - ".rspec"
150
150
  - ".travis.yml"
151
+ - CHANGELOG.md
151
152
  - Docfile
152
153
  - Gemfile
153
154
  - LICENSE.txt