rezept 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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