mkstack 1.0.0 → 1.2.1

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
  SHA256:
3
- metadata.gz: aa22c1f1c57234678eefa866bc219909dc00334d91d6d4daf70be9762233d51c
4
- data.tar.gz: c5a1f8095d6b34d467fafd443fbc9605b206a42ef70e65f47ec9290ed8783ca3
3
+ metadata.gz: 156c6f1b2ce583f7723c9943105e5a56b27959cad2dcd3cab914065806d5371b
4
+ data.tar.gz: d994eee79d71b74e2a635059ed1a4ba47cf93d518e3606421a567f6b92bd53ff
5
5
  SHA512:
6
- metadata.gz: b0a0588f47fbc38f7efddb0175afbfacb7d40604a41094a9bc705a26fc6edc154c00bc9f2146e1a19d3326d1d7bfdbb2a6f2de9918a5f8a67ca11e06e202d286
7
- data.tar.gz: b23350d9abe01bb969d9dbf617d7025f5572481e526b37a7632a6ec8fb46c7a64aebb92266166105bfd55ffd73f5187b642620d04bdf4ede746ceeb99bf696ee
6
+ metadata.gz: ab4040c5feb8d08e926c58c36ffc9c6f7f70f17c433992cfbb4b227cabf03802ad1f0139fde972847037bf466877f5d6a212f44136e4aa7709135345c7c34550
7
+ data.tar.gz: f09c970148652460c653672016f60f97feae0df146fa487be7d942ea7f98a8470ed4af47467b864b020bc19d0ef42df65295377cc0ee61bf0aa0563e6cb6f61b
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,8 +1,10 @@
1
- #!/usr/local/bin/ruby
1
+ #!/usr/bin/env ruby
2
2
 
3
3
  require "logger"
4
4
  require "optparse"
5
- require "mkstack"
5
+ require_relative "../lib/mkstack"
6
+
7
+ version = "1.2.0"
6
8
 
7
9
 
8
10
  ##################################################
@@ -15,12 +17,11 @@ $logger.formatter = proc { |s, d, p, m|
15
17
  "[%s] %5s [%5s] - %s\n" % [ d.strftime("%Y-%m-%d %H:%M:%S"), s, caller(4, 1).first.split(":")[1], m ]
16
18
  }
17
19
 
18
-
19
20
  # Default options
20
21
  options = {}
21
22
  options[:erb] = true
22
23
  options[:format] = "json"
23
-
24
+ options[:erb_argv] = []
24
25
 
25
26
  # Command line options
26
27
  opts = OptionParser.new do |p|
@@ -30,13 +31,14 @@ opts = OptionParser.new do |p|
30
31
 
31
32
  # Help
32
33
  p.on("-h", "--help", "Display this message") { puts opts ; exit }
34
+ p.on("--version", "Show version") { puts version ; exit }
33
35
  p.separator(" ")
34
36
 
35
37
  # Verbosity
36
38
  p.on("-d", "--debug", "Show debug messages") { $logger.level = Logger::DEBUG }
37
39
  p.on("-v", "--verbose", "Be verbose") { $logger.level = Logger::INFO }
38
40
  p.on("-q", "--quiet", "Only show errors") { $logger.level = Logger::ERROR }
39
- p.on("-s", "--silient", "Don't show any log messages") { $logger.level = Logger::FATAL }
41
+ p.on("-s", "--silent", "Don't show any log messages") { $logger.level = Logger::FATAL }
40
42
  p.separator(" ")
41
43
 
42
44
  # Output
@@ -49,18 +51,35 @@ opts = OptionParser.new do |p|
49
51
  # Operations
50
52
  p.on("--erb", "--[no-]erb", "Perform ERB processing (default is true)") { |x| options[:erb] = x }
51
53
  p.on("--validate", "Call ValidateTemplate after merging") { options[:validate] = true }
54
+ p.separator(" ")
55
+
56
+ # ERB options
57
+ p.on("---", "Marks end of mkstack options") { p.terminate("---") }
58
+ p.on("%s Remaining arguments are available to ERB as an Array argv" % [ desc_padding ])
52
59
  end
53
60
 
54
- files = opts.parse!.uniq
55
- opts.parse "--help" if files.count == 0
61
+ # Separate files from ERB arguments
62
+ args = opts.parse!
56
63
 
57
- template = MkStack::Template.new(options[:format])
64
+ if args.index("---")
65
+ files = args[0..(args.index("---") - 1)]
66
+ options[:erb_argv] = args[(args.index("---") + 1)..nil]
67
+ else
68
+ files = args
69
+ end
58
70
 
71
+ # At least one file is required
72
+ files.uniq!
73
+ opts.parse "--help" if ((files.count == 0) or (files[0].eql?("---")))
59
74
 
60
75
  # Merge files
76
+ template = MkStack::Template.new(options[:format], options[:erb_argv])
77
+
61
78
  files.each do |file|
62
79
  begin
63
- Dir.chdir(File.dirname(file)) { template.merge(File.basename(file), options[:erb]) }
80
+ Dir.chdir(File.dirname(file)) {
81
+ template.merge(File.basename(file), options[:erb])
82
+ }
64
83
  rescue KeyError => e
65
84
  $logger.warn { "#{file}: already parsed" }
66
85
  rescue Exception => e
@@ -68,7 +87,6 @@ files.each do |file|
68
87
  end
69
88
  end
70
89
 
71
-
72
90
  # Check limits
73
91
  $logger.debug { "Checking limits" }
74
92
 
@@ -79,19 +97,17 @@ end
79
97
  $logger.warn { "At least one Resources member must be defined" } if template["Resources"].length == 0
80
98
  $logger.warn { "Template too large (#{template.length} > #{template.limit})" } if template.exceeds_limit?
81
99
 
82
-
83
100
  # Validate template
84
101
  if options[:validate] then
85
102
  begin
86
103
  $logger.info { "Validating #{template.format} template" }
87
104
 
88
- $logger.debug { template.validate }
105
+ template.validate
89
106
  rescue Exception => e
90
107
  $logger.error { e.message }
91
108
  end
92
109
  end
93
110
 
94
-
95
111
  # Save template
96
112
  if options[:save] then
97
113
  begin
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  require_relative "mkstack/template"
2
3
 
3
4
  =begin rdoc
@@ -5,9 +6,10 @@ require_relative "mkstack/template"
5
6
  Merge multiple CloudFormation template files into a single template.
6
7
  Each file may be in either JSON or YAML format.
7
8
 
8
- Get started with <i>template = MkStack::Template.new</i>
9
+ Get started with <i>template = MkStack::Template.new</i>, or use the
10
+ command line tool <i>mkstack</i>.
9
11
 
10
- == ERB
12
+ = ERB
11
13
 
12
14
  By default all files are run through an ERB (Embedded RuBy) processor.
13
15
 
@@ -62,7 +64,9 @@ tags defined in one file to be referenced in subsequent files.
62
64
  "sg": {
63
65
  "Type" : "AWS::EC2::SecurityGroup",
64
66
  "Properties" : {
65
- "GroupDescription" : { "Fn::Sub" : "Security Group for ${application}" }
67
+ "GroupDescription" : {
68
+ "Fn::Sub" : "Security Group for ${application}"
69
+ }
66
70
  <%= tags_json %>
67
71
  }
68
72
  }
@@ -71,10 +75,39 @@ tags defined in one file to be referenced in subsequent files.
71
75
 
72
76
  Note that foo.yaml is processed <i>before</i> bar.json.
73
77
 
74
- == See Also
78
+ = Command line tool
79
+
80
+ Usage: mkstack [ options ] file1 [ file2... ]
81
+ -h, --help Display this message
82
+
83
+ -d, --debug Show debug messages
84
+ -v, --verbose Be verbose
85
+ -q, --quiet Only show errors
86
+ -s, --silent Don't show any log messages
87
+
88
+ -o, --output=FILE Print final template to FILE
89
+ Use '-' for stdout
90
+ -f, --format=FORMAT Print as FORMAT
91
+ Supported formats: json (default), yaml
92
+
93
+ ‐‐erb, --[no-]erb Perform ERB processing (default is true)
94
+ ‐‐validate Call ValidateTemplate after merging
95
+
96
+ ‐‐‐ Marks end of mkstack options
97
+ Remaining arguments are available to ERB as Array argv
98
+
99
+ == Passing arguments to ERB
100
+
101
+ Any command line arguments following "---" are added to an Array
102
+ called <b>argv</b>, which can be referenced in your ERB code.
103
+
104
+ === foo.yaml
105
+
106
+ <% puts "#{argv.class} with #{argv.length} items: #{argv}" %>
107
+ =====
108
+ $ mkstack foo.yaml --- a 2 test
109
+ Array with 3 items: ["a", "2", "test"]
75
110
 
76
- MkStack::Template
77
- MkStack::Section
78
111
  =end
79
112
 
80
113
  module MkStack
@@ -5,25 +5,49 @@ require "json"
5
5
  require "yaml"
6
6
 
7
7
  module MkStack
8
+ ##################################################
9
+ # A class to represent undefined local tags.
10
+ #
11
+ # CloudFormation uses <b>!</b> to denote the YAML short form of
12
+ # intrinsic functions, which is the same prefix YAML uses for local
13
+ # tags. The default handler strips undefined local tags, leaving
14
+ # just the value.
15
+ #
16
+ # Loading a YAML file will force the output to be in YAML format.
17
+
18
+ class IntrinsicShort
19
+ def init_with(coder)
20
+ @coder = coder
21
+ end
22
+
23
+ def encode_with(coder)
24
+ coder.tag = @coder.tag
25
+
26
+ coder.map = @coder.map if @coder.type == :map
27
+ coder.scalar = @coder.scalar if @coder.type == :scalar
28
+ coder.seq = @coder.seq if @coder.type == :seq
29
+ end
30
+ end
31
+
8
32
  ##################################################
9
33
  # A CloudFormation template
10
34
  class Template
11
35
  attr_reader :sections, :limit, :format
12
36
 
13
- def initialize(format = "json")
37
+ def initialize(format = "json", argv = nil)
14
38
  @format = format
15
39
 
16
40
  @sections = {
17
41
  "AWSTemplateFormatVersion" => Section.new("AWSTemplateFormatVersion", String, nil),
18
42
  "Description" => Section.new("Description", String, 1024),
19
43
 
20
- "Conditions" => Section.new("Conditions", Hash, nil),
21
- "Mappings" => Section.new("Mappings", Hash, 100),
22
- "Metadata" => Section.new("Metadata", Hash, nil),
23
- "Outputs" => Section.new("Outputs", Hash, 60),
24
- "Parameters" => Section.new("Parameters", Hash, 60),
25
- "Resources" => Section.new("Resources", Hash, nil),
26
- "Transforms" => Section.new("Transforms", Hash, nil),
44
+ "Conditions" => Section.new("Conditions", Hash, nil),
45
+ "Mappings" => Section.new("Mappings", Hash, 200),
46
+ "Metadata" => Section.new("Metadata", Hash, nil),
47
+ "Outputs" => Section.new("Outputs", Hash, 200),
48
+ "Parameters" => Section.new("Parameters", Hash, 200),
49
+ "Resources" => Section.new("Resources", Hash, 500),
50
+ "Transform" => Section.new("Transform", Hash, nil),
27
51
  }
28
52
  @limit = 51200
29
53
 
@@ -34,10 +58,6 @@ module MkStack
34
58
  # every time we load a file. This allows ERB code in one file to
35
59
  # be referenced in another.
36
60
  @binding = binding
37
-
38
- # See add_domain_types
39
- @yaml_domain = "mlfs.org,2019"
40
- @global_tag = "tag:#{@yaml_domain}:"
41
61
  end
42
62
 
43
63
  # Shorthand accessor for template sections
@@ -60,8 +80,9 @@ module MkStack
60
80
  cfn = JSON.load(contents)
61
81
  rescue Exception => e
62
82
  # Try YAML
63
- add_domain_types
64
- cfn = YAML.load(contents)
83
+ add_tags
84
+ cfn = YAML.safe_load(contents, [IntrinsicShort])
85
+ @format = "yaml"
65
86
  end
66
87
 
67
88
  # Merge sections that are present in the file
@@ -90,9 +111,7 @@ module MkStack
90
111
  when "json"
91
112
  to_hash.to_json
92
113
  when "yaml"
93
- # Strip enclosing quotes around tags and revert tags to their short form
94
- # And keep Psych from splitting "long" lines
95
- to_hash.to_yaml({ line_width: -1 }).gsub(/"(#{@global_tag}[^"]+?)"/, '\1').gsub("#{@global_tag}", "!")
114
+ to_hash.to_yaml({ line_width: -1 }) # Keep Psych from splitting "long" lines
96
115
  else
97
116
  to_hash
98
117
  end
@@ -127,20 +146,9 @@ module MkStack
127
146
 
128
147
 
129
148
  #########################
130
- # Define YAML domains to handle CloudFormation intrinsic
131
- # functions.
132
- #
133
- # CloudFormation uses <b>!</b> to denote the YAML short form of
134
- # intrinsic functions, which is the same prefix YAML uses for
135
- # local tags. The default handler strips undefined local tags,
136
- # leaving just the value.
137
- #
138
- # This puts the tags back, but in global tag format. The global
139
- # tag prefix is converted back to <b>!</b> on output.
140
- #
141
- # Using the short form will force the output to be in YAML format.
142
- def add_domain_types
143
- functions = [
149
+ # List of intrinsic functions that look like undefined local tags
150
+ def add_tags
151
+ [
144
152
  "Base64",
145
153
  "Cidr",
146
154
  "FindInMap",
@@ -157,21 +165,9 @@ module MkStack
157
165
  "If",
158
166
  "Not",
159
167
  "Or",
160
- ].each do |function|
161
- YAML::add_domain_type(@yaml_domain, function) do |type, val|
162
- @format = "yaml"
163
- "#{type} #{val}"
164
- end
165
- end
166
-
167
- # The syntax for !Sub requires double-quotes around Strings
168
- functions = [
169
168
  "Sub",
170
169
  ].each do |function|
171
- YAML::add_domain_type(@yaml_domain, function) do |type, val|
172
- @format = "yaml"
173
- val.is_a?(String)? "#{type} \"#{val}\"" : "#{type} #{val}"
174
- end
170
+ YAML::add_tag("!#{function}", IntrinsicShort)
175
171
  end
176
172
  end
177
173
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "mkstack"
3
- s.version = "1.0.0"
3
+ s.version = "1.2.1"
4
4
  s.summary = "Merge multiple CloudFormation template files into a single template"
5
5
  s.description = <<-EOF
6
6
  Merge multiple CloudFormation template files into a single template. Each file may be in either JSON or YAML format. By default all files are run through an ERB (Embedded RuBy) processor.
metadata CHANGED
@@ -1,18 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mkstack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Rosen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIEOjCCAqKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBphanIv
14
- REM9Y29ycC9EQz1tbGZzL0RDPW9yZzAeFw0xOTA1MDEwMjIwNTBaFw0yMDA0MzAw
15
- MjIwNTBaMCUxIzAhBgNVBAMMGmFqci9EQz1jb3JwL0RDPW1sZnMvREM9b3JnMIIB
13
+ MIID/jCCAmagAwIBAgIBAjANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBphanIv
14
+ REM9Y29ycC9EQz1tbGZzL0RDPW9yZzAeFw0yMDA2MjMyMjA0MDdaFw0yMTA2MjMy
15
+ MjA0MDdaMCUxIzAhBgNVBAMMGmFqci9EQz1jb3JwL0RDPW1sZnMvREM9b3JnMIIB
16
16
  ojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAqQ2xCUJ4wY8WujSzYd3OGTbj
17
17
  JDMeU44pXOTLc49Rs8ydukGfd0YBvYMzifmiVRj6depGx2+Ln28Y2mT6IB+zHq8X
18
18
  s1lrMdFCReztJjQ7OYS16YcZ6pmLkYClnHN3VNqayk1lQEJGCr8aawMeroSB01om
@@ -21,20 +21,19 @@ cert_chain:
21
21
  JbnFW7mFQGtBpfh8zY8OCQ76Aw8cb5bEIPTI+Hd4FoJLPKnexTI28endSLigOUCF
22
22
  76kLOiVOVOjdqZ8vEdSgWVugEAzIC30xW5b8yD6N7GdT7n3ktgoZu7jZMUW3D6PQ
23
23
  wS6BaABVsXbeVtFrzK2tQ65EwLfRluRLTfbnQ7qvMIYCwC3Ib9DTMLavCiOot1vc
24
- RBWXIrDex0tt3EN0dDIxP9O+7ciDgM4zPe6BvaF/AgMBAAGjdTBzMAkGA1UdEwQC
25
- MAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBRDowzw+kmcX6FV7T9BkQsUgmzLZjAc
26
- BgNVHREEFTATgRFhanJAY29ycC5tbGZzLm9yZzAcBgNVHRIEFTATgRFhanJAY29y
27
- cC5tbGZzLm9yZzANBgkqhkiG9w0BAQsFAAOCAYEAbbgfVpRCtujGFRHNYLWnq/iQ
28
- vGtNs265jQKdq3SZ5HIsPP4RdiknOk2Q0BP4GDkXOhadtuuqeCVlJUczcrCKiKuP
29
- Vu7iOQKpOq9bafhjvTpRPZL7uXDu0lwBrDyL9PGouBBsijTtGCc/A8cu/2HVoX+Z
30
- X1pqmuJqVlgXp9ktbzPBeIdaFFT+9WzIzWCJ73oBYNZ1EP/4CRKIlmRCWzBGZtu6
31
- QqNypgW/OCQVRcJGZ99myNQO5/EImQp1py6iHymkdCx2RMsdTUpcm3gUl4XaFd4J
32
- pQ1HNcDdD3UCSDqlPpv2nVpOV4u1s3yojIHt0RcVXhSzqGHgmXNjKDIP0zokFBKx
33
- NigI/5A3vv9PplxXMatOeirqPqDY5F4Aim4t2Dn+d+9OiPADkIBwuIuwwgRmcWhE
34
- E2DV+ftSSpAT1zeHEZXx6BsvJVwtXq1kMDYibgB4lTU4lq1oHrx2x+PO2cukHlom
35
- 4cVT/heohjMDtNBaDMVsTjTxtNq6oi/pvyLqBGmQ
24
+ RBWXIrDex0tt3EN0dDIxP9O+7ciDgM4zPe6BvaF/AgMBAAGjOTA3MAkGA1UdEwQC
25
+ MAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBRDowzw+kmcX6FV7T9BkQsUgmzLZjAN
26
+ BgkqhkiG9w0BAQsFAAOCAYEAAmnuLwfJOuo9JlIMPCArwX0wIZcuKJ1Ms5S9RpTT
27
+ MYqNwa52//SCZ5VG0bZknXNgHGs1qm4kHekxOVjjjdawVHQFZvDJJxblSvj1OTe0
28
+ J4OF7hiWldeUE7ezeHDpzcVpGkHBGYCPkLBPyjMkRwlZpgth9DVO7FP3mV9SMHyP
29
+ x1/55FYk0A62NgXSzmLghePC+trYllv54YURP4/R8RYnZPZNf5MFMjF94BoWGFzQ
30
+ 9BKJ+1DbdAVwCMSWEcGOkw5euwofwf6PpvLlmhB9pM+acsjLJkaS/OU7v5/X0F6+
31
+ MkYSejwDmyV9/u/cPgStxlOOu4x7Ur2qOzfb8OEKMmautB7ZEdCivdG/Qa634dDq
32
+ dnrb3iC4VliJf0o5SVrYjRxBYn9WQV1eJaygRunfhVo9AqRPg+rcbkQ/XIWUQDeY
33
+ kLyoFawGT9fF6+lXyIT9XiaUzOCjQUJo94on5U601Y2GXB4Sa1oxLSBlEtkSwuD3
34
+ gMHlHdBRvoJurkVzYNWkN+Cz
36
35
  -----END CERTIFICATE-----
37
- date: 2019-05-02 00:00:00.000000000 Z
36
+ date: 2020-10-23 00:00:00.000000000 Z
38
37
  dependencies:
39
38
  - !ruby/object:Gem::Dependency
40
39
  name: aws-sdk-cloudformation
@@ -54,7 +53,7 @@ description: 'Merge multiple CloudFormation template files into a single templat
54
53
  file may be in either JSON or YAML format. By default all files are run through
55
54
  an ERB (Embedded RuBy) processor.
56
55
 
57
- '
56
+ '
58
57
  email:
59
58
  - ajr@corp.mlfs.org
60
59
  executables:
@@ -71,7 +70,7 @@ homepage: https://github.com/ajrosen/AWS/tree/master/mkstack
71
70
  licenses:
72
71
  - GPL-3.0+
73
72
  metadata: {}
74
- post_install_message:
73
+ post_install_message:
75
74
  rdoc_options: []
76
75
  require_paths:
77
76
  - lib
@@ -86,9 +85,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
85
  - !ruby/object:Gem::Version
87
86
  version: '0'
88
87
  requirements: []
89
- rubyforge_project:
90
- rubygems_version: 2.7.6
91
- signing_key:
88
+ rubygems_version: 3.1.4
89
+ signing_key:
92
90
  specification_version: 4
93
91
  summary: Merge multiple CloudFormation template files into a single template
94
92
  test_files: []
metadata.gz.sig CHANGED
Binary file