rezept 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b1e46b66acf98930fd5070f065439fd87ea1418e
4
+ data.tar.gz: 5145a5beb089d59c11980b4d007b58a67f8bc9ad
5
+ SHA512:
6
+ metadata.gz: c8df9983eed7551c6715fe1c2cf9215489636d609966a532523d0a1ff51f14dff8ed09c6f3e6b73e933087d341d08aef65a549c9049d6baf15890c170ad01870
7
+ data.tar.gz: 12f87f8f44a03d21a7027988d221323c61ecea92c3bb252e4f19ba85caeccdfb6d2fedcf7b3266f3aea514c36f8b2839f62718e529e6d0c48eafa0c2e1287941
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.1.3
5
+ before_install: gem install bundler -v 1.12.5
data/Docfile ADDED
@@ -0,0 +1,61 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ template "runShellScriptTemplate" do
4
+ content do
5
+ __dsl do
6
+ schemaVersion "2.0"
7
+ description "Run a shell script"
8
+ mainSteps do |*|
9
+ action "aws:runShellScript"
10
+ name "runShellScript"
11
+ inputs do
12
+ commands __script(context.commands)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Command "My-RunShellScript" do
20
+ account_ids []
21
+ include_template "runShellScriptTemplate", commands: "echo 1"
22
+ end
23
+
24
+ Command "My-RunShellScript-2" do
25
+ account_ids []
26
+ content do
27
+ __dsl do
28
+ schemaVersion "2.0"
29
+ description "Run a shell script"
30
+ mainSteps do |*|
31
+ action "aws:runShellScript"
32
+ name "runShellScript"
33
+ inputs do
34
+ commands __script(<<-'EOS')
35
+ #! /bin/bash
36
+ echo 1
37
+ echo 2
38
+ echo 3
39
+ 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")
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rezept.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Serverworks Co.,Ltd.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,281 @@
1
+ # Rezept
2
+
3
+ A tool to manage EC2 Systems Manager (SSM) Documents with programmable DSL.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'rezept'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install rezept
20
+
21
+ ## Usage
22
+
23
+ #### General
24
+
25
+ ```
26
+ $ rezept
27
+ Commands:
28
+ rezept apply # Apply the documents
29
+ rezept convert -n, --name=NAME -t, --type=TYPE # Convert the documents to the other format
30
+ rezept export # Export the documents
31
+ rezept help [COMMAND] # Describe available commands or one specific command
32
+
33
+ Options:
34
+ -f, [--file=FILE] # Configuration file
35
+ # Default: Docfile
36
+ [--color], [--no-color] # Disable colorize
37
+ # Default: true
38
+ [--amazon-docs], [--no-amazon-docs] # Include Amazon owned documents
39
+ [--dsl-content], [--no-dsl-content] # Convert JSON contents to DSL
40
+ # Default: true
41
+ ```
42
+
43
+ #### apply
44
+ Apply the documents
45
+
46
+ ```
47
+ $ rezept help apply
48
+ Usage:
49
+ rezept apply
50
+
51
+ Options:
52
+ [--dry-run], [--no-dry-run] # Dry run (Only output the difference)
53
+ -f, [--file=FILE] # Configuration file
54
+ # Default: Docfile
55
+ [--color], [--no-color] # Disable colorize
56
+ # Default: true
57
+ [--amazon-docs], [--no-amazon-docs] # Include Amazon owned documents
58
+ [--dsl-content], [--no-dsl-content] # Convert JSON contents to DSL
59
+ # Default: true
60
+ ```
61
+
62
+ #### convert
63
+ Convert the documents to the other format
64
+
65
+ ```
66
+ $ rezept help convert
67
+ Usage:
68
+ rezept convert -n, --name=NAME -t, --type=TYPE
69
+
70
+ Options:
71
+ -n, --name=NAME # Name of document
72
+ -t, --type=TYPE # Type of document (Command|Automation)
73
+ [--format=FORMAT] # Output format (json|ruby)
74
+ -o, [--output=OUTPUT] # Output filename (path)
75
+ -f, [--file=FILE] # Configuration file
76
+ # Default: Docfile
77
+ [--color], [--no-color] # Disable colorize
78
+ # Default: true
79
+ [--amazon-docs], [--no-amazon-docs] # Include Amazon owned documents
80
+ [--dsl-content], [--no-dsl-content] # Convert JSON contents to DSL
81
+ # Default: true
82
+ ```
83
+
84
+ #### export
85
+ Export the documents
86
+
87
+ ```
88
+ $ rezept help export
89
+ Usage:
90
+ rezept export
91
+
92
+ Options:
93
+ [--write], [--no-write] # Write the documents to the file
94
+ [--split], [--no-split] # Split file by the documents
95
+ -f, [--file=FILE] # Configuration file
96
+ # Default: Docfile
97
+ [--color], [--no-color] # Disable colorize
98
+ # Default: true
99
+ [--amazon-docs], [--no-amazon-docs] # Include Amazon owned documents
100
+ [--dsl-content], [--no-dsl-content] # Convert JSON contents to DSL
101
+ # Default: true
102
+ ```
103
+
104
+ ## Advanced methods
105
+
106
+ #### Script styled commands (__script)
107
+
108
+ - Docfile
109
+
110
+ ```
111
+ Command "My-RunShellScript" do
112
+ account_ids []
113
+ content do
114
+ __dsl do
115
+ schemaVersion "2.0"
116
+ description "my Run a shell script or specify the path to a script to run."
117
+ mainSteps do |*|
118
+ action "aws:runShellScript"
119
+ name "runShellScript"
120
+ inputs do
121
+ commands __script(<<-'EOS')
122
+ #! /bin/bash
123
+ echo 1
124
+ echo 2
125
+ echo 3
126
+ EOS
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ ```
133
+
134
+ - Result
135
+
136
+ ```sh
137
+ $ rezept convert -n My-RunShellScript -t Command --format json
138
+ Document: 'My-RunShellScript'
139
+ Document Type: 'Command'
140
+ {
141
+ "schemaVersion": "2.0",
142
+ "description": "Run a shell script",
143
+ "mainSteps": [
144
+ {
145
+ "action": "aws:runShellScript",
146
+ "name": "runShellScript",
147
+ "inputs": {
148
+ "commands": [
149
+ "#! /bin/bash",
150
+ "echo 1",
151
+ "echo 2",
152
+ "echo 3"
153
+ ]
154
+ }
155
+ }
156
+ ]
157
+ }
158
+ ```
159
+
160
+ #### Commands from the other script file (__script_file)
161
+
162
+ - Docfile
163
+
164
+ ```
165
+ Command "My-RunShellScript" do
166
+ account_ids []
167
+ content do
168
+ __dsl do
169
+ schemaVersion "2.0"
170
+ description "my Run a shell script or specify the path to a script to run."
171
+ mainSteps do |*|
172
+ action "aws:runShellScript"
173
+ name "runShellScript"
174
+ inputs do
175
+ commands __script_file("script.sh")
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+ ```
182
+
183
+ - script.sh
184
+
185
+ ```sh
186
+ #! /bin/bash
187
+ echo 1
188
+ echo 2
189
+ echo 3
190
+ ```
191
+
192
+ - Result
193
+
194
+ ```sh
195
+ $ rezept convert -n My-RunShellScript -t Command --format json
196
+ Document: 'My-RunShellScript'
197
+ Document Type: 'Command'
198
+ {
199
+ "schemaVersion": "2.0",
200
+ "description": "Run a shell script",
201
+ "mainSteps": [
202
+ {
203
+ "action": "aws:runShellScript",
204
+ "name": "runShellScript",
205
+ "inputs": {
206
+ "commands": [
207
+ "#! /bin/bash",
208
+ "echo 1",
209
+ "echo 2",
210
+ "echo 3"
211
+ ]
212
+ }
213
+ }
214
+ ]
215
+ }
216
+ ```
217
+
218
+ #### Templating
219
+
220
+ - Docfile
221
+
222
+ ```ruby
223
+ template "runShellScriptTemplate" do
224
+ content do
225
+ __dsl do
226
+ schemaVersion "2.0"
227
+ description "Run a shell script"
228
+ mainSteps do |*|
229
+ action "aws:runShellScript"
230
+ name "runShellScript"
231
+ inputs do
232
+ commands __script(context.commands)
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
238
+
239
+ Command "My-RunShellScript" do
240
+ account_ids []
241
+ include_template "runShellScriptTemplate", commands: "echo 1"
242
+ end
243
+ ```
244
+
245
+ - Result
246
+
247
+ ```sh
248
+ $ rezept convert -n My-RunShellScript -t Command --format json
249
+ Document: 'My-RunShellScript'
250
+ Document Type: 'Command'
251
+ {
252
+ "schemaVersion": "2.0",
253
+ "description": "Run a shell script",
254
+ "mainSteps": [
255
+ {
256
+ "action": "aws:runShellScript",
257
+ "name": "runShellScript",
258
+ "inputs": {
259
+ "commands": [
260
+ "echo 1"
261
+ ]
262
+ }
263
+ }
264
+ ]
265
+ }
266
+ ```
267
+
268
+ ## Development
269
+
270
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
271
+
272
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
273
+
274
+ ## Contributing
275
+
276
+ Bug reports and pull requests are welcome on GitHub at https://github.com/serverworks/rezept. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
277
+
278
+
279
+ ## License
280
+
281
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rezept"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/rezept ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'rezept'
6
+
7
+ Rezept::Cli.start(ARGV)
@@ -0,0 +1,133 @@
1
+ require 'yaml'
2
+ require 'json'
3
+
4
+ module Rezept
5
+ class Actions
6
+ include Rezept::Logger::Helper
7
+
8
+ def initialize(client, converter)
9
+ @client = client
10
+ @converter = converter
11
+ end
12
+
13
+ def export(options)
14
+ @converter.set_options(options)
15
+ @client.set_options(options)
16
+ docs = @client.get_documents
17
+
18
+ if options['write']
19
+ if options['split']
20
+ content = ''
21
+ docs.each do |doc|
22
+ name = @converter.filename(doc.name)
23
+ _export_dsl_file(@converter.to_dsl(doc), "#{name}.rb")
24
+ content << "require #{name.inspect}\n"
25
+ end
26
+ _export_dsl_file(content, options['file'])
27
+ else
28
+ _export_dsl_file(@converter.to_dsl_all(docs), options['file'])
29
+ end
30
+ else
31
+ Rezept::Utils.print_ruby(@converter.to_dsl_all(docs), color: options['color'])
32
+ end
33
+ end
34
+
35
+ def apply(options)
36
+ @converter.set_options(options)
37
+ @client.set_options(options)
38
+ dry_run = options['dry_run'] ? '[Dry run] ' : ''
39
+ _apply_docs(@converter.dslfile_to_h(options['file']), @client.get_documents, dry_run)
40
+ end
41
+
42
+ def convert(options)
43
+ @converter.set_options(options)
44
+
45
+ fmt = 'unknown'
46
+
47
+ if not options['format'].nil?
48
+ fmt = options['format']
49
+ elsif options['file'] =~ /\.(json|template)$/
50
+ fmt = 'ruby'
51
+ end
52
+
53
+ info("Document: '#{options['name']}'")
54
+ info("Document Type: '#{options['type']}'")
55
+
56
+ case fmt
57
+ when 'json'
58
+ docs = @converter.dslfile_to_h(options['file'])
59
+ docs = docs.select {|d| d['name'] == options['name'] }
60
+ ret = JSON.pretty_generate(JSON.parse(docs[0]['content']))
61
+ Rezept::Utils.print_json(ret)
62
+ when 'ruby'
63
+ doc = {}
64
+ doc['name'] = options['name']
65
+ doc['document_type'] = options['type']
66
+ doc['content'] = File.read(options['file'])
67
+ ret = @converter.to_dsl(doc)
68
+ Rezept::Utils.print_ruby(ret)
69
+ else
70
+ raise "Unsupported format '#{fmt}'"
71
+ end
72
+ _export_file(ret, options['output']) unless options['output'].nil?
73
+ end
74
+
75
+ def _apply_docs(local, remote, dry_run)
76
+ local.each do |l|
77
+ l_ids = l.delete('account_ids')
78
+ r_ids = []
79
+ r = _choice_by_name(remote, l['name'])
80
+
81
+ if r.nil?
82
+ info("#{dry_run}Create the new document #{l['name'].inspect}")
83
+ @client.create_document(l) if dry_run.empty?
84
+ else
85
+ r_ids = r.delete('account_ids')
86
+ diff = Rezept::Utils.diff(@converter, r, l)
87
+
88
+ if diff == "\n"
89
+ info("#{dry_run}No changes '#{l['name']}'")
90
+ else
91
+ warn("#{dry_run}Update the document #{l['name'].inspect}")
92
+ STDERR.puts diff
93
+ @client.version_up_document(l) if dry_run.empty?
94
+ end
95
+ end
96
+
97
+ add_ids = l_ids - r_ids
98
+ del_ids = r_ids - l_ids
99
+ info("#{dry_run}Add permission of #{l['name'].inspect} to #{add_ids.join(', ')}") if add_ids.length > 0
100
+ warn("#{dry_run}Remove permission of #{l['name'].inspect} from #{add_ids.join(', ')}") if del_ids.length > 0
101
+ @client.modify_document_permission(l, add_ids, del_ids) if dry_run.empty?
102
+ end
103
+
104
+ remote.each do |r|
105
+ if _choice_by_name(local, r['name']).nil?
106
+ warn("#{dry_run}Delete the document #{r['name'].inspect}")
107
+ @client.delete_document(r) if dry_run.empty?
108
+ end
109
+ end
110
+ end
111
+
112
+ def _choice_by_name(docs, name)
113
+ docs.each do |d|
114
+ return d if d['name'] == name
115
+ end
116
+ nil
117
+ end
118
+
119
+ def _export_dsl_file(dsl, filename)
120
+ dsl = <<-EOS
121
+ #! /usr/bin/env ruby
122
+
123
+ #{dsl}
124
+ EOS
125
+ _export_file(dsl, filename)
126
+ end
127
+
128
+ def _export_file(dsl, filename)
129
+ File.write(filename, dsl)
130
+ info("Write #{filename.inspect}")
131
+ end
132
+ end
133
+ end
data/lib/rezept/cli.rb ADDED
@@ -0,0 +1,40 @@
1
+ require 'thor'
2
+
3
+ module Rezept
4
+ class Cli < Thor
5
+ class_option :file, aliases: '-f', desc: 'Configuration file', type: :string, default: 'Docfile'
6
+ class_option :color, desc: 'Disable colorize', type: :boolean, default: $stdout.tty?
7
+ class_option :amazon_docs, desc: 'Include Amazon owned documents', type: :boolean, default: false
8
+ class_option :dsl_content, desc: 'Convert JSON contents to DSL', type: :boolean, default: true
9
+
10
+ def initialize(*args)
11
+ @actions = Rezept::Actions.new(
12
+ Rezept::Client.new,
13
+ Rezept::Converter.new
14
+ )
15
+ super(*args)
16
+ end
17
+
18
+ desc "export", "Export the documents"
19
+ option :write, desc: 'Write the documents to the file', type: :boolean, default: false
20
+ option :split, desc: 'Split file by the documents', type: :boolean, default: false
21
+ def export
22
+ @actions.export(options)
23
+ end
24
+
25
+ desc "apply", "Apply the documents"
26
+ option :dry_run, desc: 'Dry run (Only output the difference)', type: :boolean, default: false
27
+ def apply
28
+ @actions.apply(options)
29
+ end
30
+
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
34
+ option :format, desc: 'Output format (json|ruby)', type: :string
35
+ option :output, aliases: '-o', desc: 'Output filename (path)', type: :string
36
+ def convert
37
+ @actions.convert(options)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,64 @@
1
+ require 'aws-sdk'
2
+
3
+ module Rezept
4
+ class Client
5
+
6
+ def initialize
7
+ @ssm = Aws::SSM::Client.new
8
+ end
9
+
10
+ def set_options(options)
11
+ @options = options
12
+ end
13
+
14
+ def get_documents(next_token = nil)
15
+ docs = []
16
+ list_documents.each do |doc|
17
+ doc = doc.to_h
18
+ doc['content'] = @ssm.get_document(
19
+ name: doc[:name], document_version: doc[:document_version]).content
20
+ doc.merge!(@ssm.describe_document_permission(name: doc[:name], permission_type: 'Share').to_h)
21
+ doc = Hash[ doc.to_h.map{|k,v| [k.to_s, v] } ]
22
+ docs << doc
23
+ end
24
+ docs
25
+ end
26
+
27
+ def list_documents(next_token = nil)
28
+ opt = {}
29
+ opt[:max_results] = 50
30
+ opt[:next_token] = next_token unless next_token.nil?
31
+
32
+ ret = @ssm.list_documents(opt)
33
+ ret.document_identifiers.concat(list_docs(ret.next_token)) unless ret.next_token.nil?
34
+ ret.document_identifiers.reject{|d| d.owner == 'Amazon' and not @options['amazon_docs'] }
35
+ end
36
+
37
+ def create_document(doc)
38
+ @ssm.create_document(
39
+ name: doc['name'], document_type: doc['document_type'], content: doc['content'])
40
+ end
41
+
42
+ def version_up_document(doc)
43
+ @ssm.update_document_default_version(
44
+ name: doc['name'],
45
+ document_version: @ssm.update_document(
46
+ name: doc['name'], content: doc['content'], document_version: '$LATEST'
47
+ ).document_description.document_version
48
+ )
49
+ end
50
+
51
+ def delete_document(doc)
52
+ @ssm.delete_document(name: doc['name'])
53
+ end
54
+
55
+ def modify_document_permission(doc, add_ids, rm_ids)
56
+ @ssm.modify_document_permission(
57
+ name: doc['name'],
58
+ permission_type: 'Share',
59
+ account_ids_to_add: add_ids,
60
+ account_ids_to_remove: rm_ids)
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,70 @@
1
+ require 'dslh'
2
+
3
+ module Rezept
4
+ class Converter
5
+
6
+ def set_options(options)
7
+ @options = options
8
+ end
9
+
10
+ def to_dsl_all(docs)
11
+ dsls = []
12
+ docs.each do |doc|
13
+ dsls << to_dsl(doc)
14
+ end
15
+ dsls.join("\n")
16
+ end
17
+
18
+ def to_dsl(doc)
19
+ exclude_key = proc do |k|
20
+ false
21
+ end
22
+
23
+ key_conv = proc do |k|
24
+ k = k.to_s
25
+ if k !~ /\A[_a-z]\w+\Z/i
26
+ "_(#{k.inspect})"
27
+ else
28
+ k
29
+ end
30
+ end
31
+
32
+ name = doc['name']
33
+ document_type = doc['document_type']
34
+
35
+ hash = {}
36
+ hash['account_ids'] = doc['account_ids']
37
+ hash['content'] = doc['content']
38
+
39
+ if doc['content'].kind_of?(String)
40
+ if @options['dsl_content']
41
+ hash['content'] = { __dsl: JSON.parse(doc['content']) }
42
+ else
43
+ hash['content'] = doc['content'].gsub(/\R$/, '')
44
+ end
45
+ end
46
+
47
+ dsl = Dslh.deval(
48
+ hash,
49
+ exclude_key: exclude_key,
50
+ use_heredoc_for_multi_line: true,
51
+ key_conv: key_conv,
52
+ initial_depth: 1
53
+ )
54
+ <<-EOS
55
+ #{document_type} #{name.inspect} do
56
+ #{dsl}
57
+ end
58
+ EOS
59
+ end
60
+
61
+ def dslfile_to_h(dsl_file)
62
+ context = DSLContext.new
63
+ context.eval_dsl(dsl_file)
64
+ end
65
+
66
+ def filename(name)
67
+ name.gsub!(/\W+/, '_')
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,87 @@
1
+ require 'hashie'
2
+
3
+ module Rezept
4
+ class DSLContext
5
+ def initialize
6
+ @docs = []
7
+ @templates = {}
8
+ @context = Hashie::Mash.new()
9
+ end
10
+
11
+ def eval_dsl(dsl_file)
12
+ @_dsl_file = dsl_file
13
+ instance_eval(File.read(dsl_file), dsl_file)
14
+ @docs
15
+ end
16
+
17
+ def method_missing(method_name, *args, &block)
18
+ if [:Automation, :Command, :Policy].include?(method_name)
19
+ hash = dslh_eval(block)
20
+ hash['name'] = args[0]
21
+ hash['document_type'] = method_name.to_s
22
+ @docs << hash
23
+ else
24
+ super
25
+ end
26
+ end
27
+
28
+ def template(name, &block)
29
+ @templates[name.to_s] = block
30
+ end
31
+
32
+ def context
33
+ @context
34
+ end
35
+
36
+ def require(file)
37
+ docfile = (file =~ %r|\A/|) ? file : File.expand_path(File.join(File.dirname(@_dsl_file), file))
38
+
39
+ if File.exist?(docfile)
40
+ instance_eval(File.read(docfile), docfile)
41
+ elsif File.exist?(docfile + '.rb')
42
+ instance_eval(File.read(docfile + '.rb'), docfile + '.rb')
43
+ else
44
+ Kernel.require(file)
45
+ end
46
+ end
47
+
48
+ def dslh_eval(block)
49
+ scope_hook = proc do |scope|
50
+ scope.instance_eval(<<-'EOS')
51
+ def include_template(template_name, context = {})
52
+ tmplt = @templates[template_name.to_s]
53
+
54
+ unless tmplt
55
+ raise "Template '#{template_name}' is not defined"
56
+ end
57
+
58
+ context_orig = @context
59
+ @context = @context.merge(context)
60
+ instance_eval(&tmplt)
61
+ @context = context_orig
62
+ end
63
+
64
+ def context
65
+ @context
66
+ end
67
+
68
+ def __dsl(&block)
69
+ @__hash__ = JSON.generate(Dslh::ScopeBlock.nest(binding, 'block'))
70
+ end
71
+
72
+ def __script(str)
73
+ str.split(/\R/)
74
+ end
75
+
76
+ def __script_file(file)
77
+ File.read(file).split(/\R/)
78
+ end
79
+ EOS
80
+ end
81
+
82
+ scope_vars = {templates: @templates, context: @context}
83
+
84
+ Dslh.eval(allow_empty_args: true, scope_hook: scope_hook, scope_vars: scope_vars, &block)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,86 @@
1
+ require 'logger'
2
+ require 'singleton'
3
+
4
+ module Rezept
5
+ class TermColor
6
+ class << self
7
+
8
+ def green(msg)
9
+ colorize 32, msg
10
+ end
11
+
12
+ def yellow(msg)
13
+ colorize 33, msg
14
+ end
15
+
16
+ def red(msg)
17
+ colorize 31, msg
18
+ end
19
+
20
+ def colorize(num, msg)
21
+ "\e[#{num}m#{msg}\e[0m"
22
+ end
23
+
24
+ end
25
+ end
26
+
27
+ class Logger < Logger
28
+ include Singleton
29
+
30
+ def initialize
31
+ super(STDERR)
32
+
33
+ self.formatter = proc do |severity, datetime, progname, msg|
34
+ "#{msg}\n"
35
+ end
36
+
37
+ self.level = Logger::INFO
38
+ end
39
+
40
+ def debug(progname = nil, method_name = nil, msg)
41
+ super(progname) { { method_name: method_name, message: msg } }
42
+ end
43
+
44
+ def info(msg)
45
+ super { Rezept::TermColor.green(msg) }
46
+ end
47
+
48
+ def warn(msg)
49
+ super { Rezept::TermColor.yellow(msg) }
50
+ end
51
+
52
+ def fatal(msg)
53
+ super { Rezept::TermColor.red(msg) }
54
+ end
55
+
56
+ def error(progname = nil, method_name = nil, msg, backtrace)
57
+ super(progname) { { method_name: method_name, message: msg, backtrace: backtrace } }
58
+ end
59
+
60
+ module Helper
61
+
62
+ def log(level, message)
63
+ logger = Rezept::Logger.instance
64
+ logger.send(level, message)
65
+ end
66
+
67
+ def info(msg)
68
+ log(:info, msg)
69
+ end
70
+
71
+ def warn(msg)
72
+ log(:warn, msg)
73
+ end
74
+
75
+ def fatal(msg)
76
+ log(:error, msg)
77
+ end
78
+
79
+ def debug(msg)
80
+ log(:debug, msg)
81
+ end
82
+
83
+ module_function :log, :info, :warn, :fatal, :debug
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,32 @@
1
+ require 'json'
2
+ require 'diffy'
3
+ require 'coderay'
4
+
5
+ module Rezept
6
+ class Utils
7
+
8
+ def self.diff(converter, hash1, hash2)
9
+ Diffy::Diff.new(
10
+ converter.to_dsl(hash1),
11
+ converter.to_dsl(hash2),
12
+ :diff => '-u'
13
+ ).to_s(:color)
14
+ end
15
+
16
+ def self.print_ruby(ruby, color=false)
17
+ if color
18
+ puts CodeRay.scan(ruby, :ruby).terminal
19
+ else
20
+ puts ruby
21
+ end
22
+ end
23
+
24
+ def self.print_json(json, color=false)
25
+ if color
26
+ puts CodeRay.scan(json, :json).terminal
27
+ else
28
+ puts json
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module Rezept
2
+ VERSION = "0.0.2"
3
+ end
data/lib/rezept.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'rezept/version'
2
+
3
+ require 'rezept/logger'
4
+ require 'rezept/utils'
5
+
6
+ require 'rezept/actions'
7
+ require 'rezept/cli'
8
+ require 'rezept/client'
9
+ require 'rezept/converter'
10
+ require 'rezept/dsl_context'
11
+
12
+ module Rezept
13
+ # Your code goes here...
14
+ end
data/rezept.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rezept/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rezept"
8
+ spec.version = Rezept::VERSION
9
+ spec.authors = ["Serverworks Co.,Ltd."]
10
+ spec.email = ["terui@serverworks.co.jp"]
11
+
12
+ spec.summary = %q{A tool to manage EC2 Systems Manager (SSM) Documents with programmable DSL. }
13
+ spec.description = %q{A tool to manage EC2 Systems Manager (SSM) Documents with programmable DSL. }
14
+ spec.homepage = "https://github.com/serverworks/rezept"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|Docfile)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "aws-sdk", "~> 2.7.4"
23
+ spec.add_dependency "dslh", ">= 0.4.8"
24
+ spec.add_dependency "thor"
25
+ spec.add_dependency "coderay"
26
+ spec.add_dependency "diffy"
27
+ spec.add_dependency "hashie"
28
+
29
+ spec.add_development_dependency "bundler", "~> 1.12"
30
+ spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "rspec", "~> 3.0"
32
+ end
metadata ADDED
@@ -0,0 +1,193 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rezept
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Serverworks Co.,Ltd.
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-02-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.7.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.7.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: dslh
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.4.8
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.4.8
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: coderay
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: diffy
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: hashie
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.12'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.12'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
139
+ description: 'A tool to manage EC2 Systems Manager (SSM) Documents with programmable
140
+ DSL. '
141
+ email:
142
+ - terui@serverworks.co.jp
143
+ executables:
144
+ - rezept
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - ".gitignore"
149
+ - ".rspec"
150
+ - ".travis.yml"
151
+ - Docfile
152
+ - Gemfile
153
+ - LICENSE.txt
154
+ - README.md
155
+ - Rakefile
156
+ - bin/console
157
+ - bin/setup
158
+ - exe/rezept
159
+ - lib/rezept.rb
160
+ - lib/rezept/actions.rb
161
+ - lib/rezept/cli.rb
162
+ - lib/rezept/client.rb
163
+ - lib/rezept/converter.rb
164
+ - lib/rezept/dsl_context.rb
165
+ - lib/rezept/logger.rb
166
+ - lib/rezept/utils.rb
167
+ - lib/rezept/version.rb
168
+ - rezept.gemspec
169
+ homepage: https://github.com/serverworks/rezept
170
+ licenses:
171
+ - MIT
172
+ metadata: {}
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ requirements: []
188
+ rubyforge_project:
189
+ rubygems_version: 2.2.2
190
+ signing_key:
191
+ specification_version: 4
192
+ summary: A tool to manage EC2 Systems Manager (SSM) Documents with programmable DSL.
193
+ test_files: []