mkstack 1.0.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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/bin/mkstack +106 -0
- data/lib/mkstack.rb +81 -0
- data/lib/mkstack/section.rb +32 -0
- data/lib/mkstack/template.rb +178 -0
- data/mkstack.gemspec +18 -0
- metadata +94 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: aa22c1f1c57234678eefa866bc219909dc00334d91d6d4daf70be9762233d51c
|
4
|
+
data.tar.gz: c5a1f8095d6b34d467fafd443fbc9605b206a42ef70e65f47ec9290ed8783ca3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b0a0588f47fbc38f7efddb0175afbfacb7d40604a41094a9bc705a26fc6edc154c00bc9f2146e1a19d3326d1d7bfdbb2a6f2de9918a5f8a67ca11e06e202d286
|
7
|
+
data.tar.gz: b23350d9abe01bb969d9dbf617d7025f5572481e526b37a7632a6ec8fb46c7a64aebb92266166105bfd55ffd73f5187b642620d04bdf4ede746ceeb99bf696ee
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
Binary file
|
data/bin/mkstack
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
require "optparse"
|
5
|
+
require "mkstack"
|
6
|
+
|
7
|
+
|
8
|
+
##################################################
|
9
|
+
# Main
|
10
|
+
|
11
|
+
# Define logger
|
12
|
+
$logger = Logger.new(STDERR)
|
13
|
+
$logger.level = Logger::WARN
|
14
|
+
$logger.formatter = proc { |s, d, p, m|
|
15
|
+
"[%s] %5s [%5s] - %s\n" % [ d.strftime("%Y-%m-%d %H:%M:%S"), s, caller(4, 1).first.split(":")[1], m ]
|
16
|
+
}
|
17
|
+
|
18
|
+
|
19
|
+
# Default options
|
20
|
+
options = {}
|
21
|
+
options[:erb] = true
|
22
|
+
options[:format] = "json"
|
23
|
+
|
24
|
+
|
25
|
+
# Command line options
|
26
|
+
opts = OptionParser.new do |p|
|
27
|
+
desc_padding = " " * (p.summary_indent.length + p.summary_width)
|
28
|
+
|
29
|
+
p.banner = "Usage: #{p.program_name} [ options ] file1 [ file2... ]"
|
30
|
+
|
31
|
+
# Help
|
32
|
+
p.on("-h", "--help", "Display this message") { puts opts ; exit }
|
33
|
+
p.separator(" ")
|
34
|
+
|
35
|
+
# Verbosity
|
36
|
+
p.on("-d", "--debug", "Show debug messages") { $logger.level = Logger::DEBUG }
|
37
|
+
p.on("-v", "--verbose", "Be verbose") { $logger.level = Logger::INFO }
|
38
|
+
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 }
|
40
|
+
p.separator(" ")
|
41
|
+
|
42
|
+
# Output
|
43
|
+
p.on("-o", "--output=FILE", "Print final template to FILE") { |x| options[:save] = x }
|
44
|
+
p.on("%s Use '-' for stdout" % [ desc_padding ])
|
45
|
+
p.on("-f", "--format=FORMAT", [ "json", "yaml" ], "Print as FORMAT") { |x| options[:format] = x }
|
46
|
+
p.on("%s Supported formats: json (default), yaml" % [ desc_padding ])
|
47
|
+
p.separator(" ")
|
48
|
+
|
49
|
+
# Operations
|
50
|
+
p.on("--erb", "--[no-]erb", "Perform ERB processing (default is true)") { |x| options[:erb] = x }
|
51
|
+
p.on("--validate", "Call ValidateTemplate after merging") { options[:validate] = true }
|
52
|
+
end
|
53
|
+
|
54
|
+
files = opts.parse!.uniq
|
55
|
+
opts.parse "--help" if files.count == 0
|
56
|
+
|
57
|
+
template = MkStack::Template.new(options[:format])
|
58
|
+
|
59
|
+
|
60
|
+
# Merge files
|
61
|
+
files.each do |file|
|
62
|
+
begin
|
63
|
+
Dir.chdir(File.dirname(file)) { template.merge(File.basename(file), options[:erb]) }
|
64
|
+
rescue KeyError => e
|
65
|
+
$logger.warn { "#{file}: already parsed" }
|
66
|
+
rescue Exception => e
|
67
|
+
$logger.error { e.message }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Check limits
|
73
|
+
$logger.debug { "Checking limits" }
|
74
|
+
|
75
|
+
template.sections.each do |name, section|
|
76
|
+
$logger.warn { "#{name} limit exceeded: (#{section.length} > #{section.limit})" } if section.exceeds_limit?
|
77
|
+
end
|
78
|
+
|
79
|
+
$logger.warn { "At least one Resources member must be defined" } if template["Resources"].length == 0
|
80
|
+
$logger.warn { "Template too large (#{template.length} > #{template.limit})" } if template.exceeds_limit?
|
81
|
+
|
82
|
+
|
83
|
+
# Validate template
|
84
|
+
if options[:validate] then
|
85
|
+
begin
|
86
|
+
$logger.info { "Validating #{template.format} template" }
|
87
|
+
|
88
|
+
$logger.debug { template.validate }
|
89
|
+
rescue Exception => e
|
90
|
+
$logger.error { e.message }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# Save template
|
96
|
+
if options[:save] then
|
97
|
+
begin
|
98
|
+
$stdout = File.new(options[:save], File::CREAT | File::WRONLY) unless options[:save] == "-"
|
99
|
+
|
100
|
+
$logger.info { "Saving #{template.format} to #{$stdout.path}" } unless $stdout == STDOUT
|
101
|
+
|
102
|
+
puts template.pp
|
103
|
+
rescue Exception => e
|
104
|
+
$logger.error { e.message }
|
105
|
+
end
|
106
|
+
end
|
data/lib/mkstack.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require_relative "mkstack/template"
|
2
|
+
|
3
|
+
=begin rdoc
|
4
|
+
|
5
|
+
Merge multiple CloudFormation template files into a single template.
|
6
|
+
Each file may be in either JSON or YAML format.
|
7
|
+
|
8
|
+
Get started with <i>template = MkStack::Template.new</i>
|
9
|
+
|
10
|
+
== ERB
|
11
|
+
|
12
|
+
By default all files are run through an ERB (Embedded RuBy) processor.
|
13
|
+
|
14
|
+
<% desc = "awesome" %>
|
15
|
+
|
16
|
+
AWSTemplateFormatVersion: "2010-09-09"
|
17
|
+
Description: My <%= desc %> CloudFormation template
|
18
|
+
|
19
|
+
It is safe to leave this enabled. If a file doesn't have any ERB tags
|
20
|
+
it is passed through untouched.
|
21
|
+
|
22
|
+
== Include
|
23
|
+
|
24
|
+
MkStack searches each file for a section named <b>Include</b>, which should
|
25
|
+
be a list of filenames. These function the same as adding the listed
|
26
|
+
files on the command line.
|
27
|
+
|
28
|
+
=== JSON
|
29
|
+
|
30
|
+
"Include" : [
|
31
|
+
"foo.yaml",
|
32
|
+
"bar.json"
|
33
|
+
]
|
34
|
+
|
35
|
+
=== YAML
|
36
|
+
|
37
|
+
Include:
|
38
|
+
- foo.yaml
|
39
|
+
- bar.json
|
40
|
+
|
41
|
+
== ERB and Include working together
|
42
|
+
|
43
|
+
MkStack uses a single <i>binding</i> for all files. This allows ERB
|
44
|
+
tags defined in one file to be referenced in subsequent files.
|
45
|
+
|
46
|
+
=== foo.yaml
|
47
|
+
|
48
|
+
Include:
|
49
|
+
- bar.json
|
50
|
+
|
51
|
+
<% tags_json = %q{
|
52
|
+
"Tags": [
|
53
|
+
{ "Key" : "application", "Value" : "mkstack" }
|
54
|
+
]
|
55
|
+
}
|
56
|
+
%>
|
57
|
+
|
58
|
+
=== bar.json
|
59
|
+
|
60
|
+
{
|
61
|
+
"Resources" : {
|
62
|
+
"sg": {
|
63
|
+
"Type" : "AWS::EC2::SecurityGroup",
|
64
|
+
"Properties" : {
|
65
|
+
"GroupDescription" : { "Fn::Sub" : "Security Group for ${application}" }
|
66
|
+
<%= tags_json %>
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
Note that foo.yaml is processed <i>before</i> bar.json.
|
73
|
+
|
74
|
+
== See Also
|
75
|
+
|
76
|
+
MkStack::Template
|
77
|
+
MkStack::Section
|
78
|
+
=end
|
79
|
+
|
80
|
+
module MkStack
|
81
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module MkStack
|
2
|
+
##################################################
|
3
|
+
# A CloudFormation template section
|
4
|
+
class Section
|
5
|
+
attr_reader :name, :limit
|
6
|
+
attr_accessor :contents
|
7
|
+
|
8
|
+
# * name: The section's name (Resources, Outputs, etc.)
|
9
|
+
# * type: The section's type (Hash or String)
|
10
|
+
# * limit: The AWS limit for this section, if any
|
11
|
+
def initialize(name, type, limit = nil)
|
12
|
+
@name = name
|
13
|
+
@limit = limit
|
14
|
+
|
15
|
+
@contents = type.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# Merge or override a section snippet
|
19
|
+
def merge(contents)
|
20
|
+
raise TypeError.new("#{contents.class} != #{@contents.class}") if contents.class != @contents.class
|
21
|
+
|
22
|
+
return @contents.merge!(contents) if @contents.respond_to?(:merge!)
|
23
|
+
@contents = contents
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return the length of the section's contents
|
27
|
+
def length; @contents.length; end
|
28
|
+
|
29
|
+
# Check if the section exceeds the AWS limit
|
30
|
+
def exceeds_limit?; @limit && length > @limit; end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require_relative "section"
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
require "json"
|
5
|
+
require "yaml"
|
6
|
+
|
7
|
+
module MkStack
|
8
|
+
##################################################
|
9
|
+
# A CloudFormation template
|
10
|
+
class Template
|
11
|
+
attr_reader :sections, :limit, :format
|
12
|
+
|
13
|
+
def initialize(format = "json")
|
14
|
+
@format = format
|
15
|
+
|
16
|
+
@sections = {
|
17
|
+
"AWSTemplateFormatVersion" => Section.new("AWSTemplateFormatVersion", String, nil),
|
18
|
+
"Description" => Section.new("Description", String, 1024),
|
19
|
+
|
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),
|
27
|
+
}
|
28
|
+
@limit = 51200
|
29
|
+
|
30
|
+
# Keep track of parsed files to avoid loops
|
31
|
+
@parsed = {}
|
32
|
+
|
33
|
+
# Save a binding so ERB can reuse it instead of creating a new one
|
34
|
+
# every time we load a file. This allows ERB code in one file to
|
35
|
+
# be referenced in another.
|
36
|
+
@binding = binding
|
37
|
+
|
38
|
+
# See add_domain_types
|
39
|
+
@yaml_domain = "mlfs.org,2019"
|
40
|
+
@global_tag = "tag:#{@yaml_domain}:"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Shorthand accessor for template sections
|
44
|
+
def [](section); @sections[section]; end
|
45
|
+
|
46
|
+
# Return the length of the entire template
|
47
|
+
def length; to_json.to_s.length; end
|
48
|
+
|
49
|
+
# Check if the template exceeds the AWS limit
|
50
|
+
def exceeds_limit?; limit && length > limit; end
|
51
|
+
|
52
|
+
|
53
|
+
#########################
|
54
|
+
# Merge contents of a file
|
55
|
+
def merge(file, erb)
|
56
|
+
contents = load(file, erb)
|
57
|
+
|
58
|
+
begin
|
59
|
+
# Try JSON
|
60
|
+
cfn = JSON.load(contents)
|
61
|
+
rescue Exception => e
|
62
|
+
# Try YAML
|
63
|
+
add_domain_types
|
64
|
+
cfn = YAML.load(contents)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Merge sections that are present in the file
|
68
|
+
@sections.each { |name, section| section.merge(cfn[name]) if cfn[name] }
|
69
|
+
|
70
|
+
# Look for Includes and merge them
|
71
|
+
# Files are Included relative to the file with the Include directive
|
72
|
+
cfn["Include"].each do |file|
|
73
|
+
Dir.chdir(File.dirname(file)) { self.merge(File.basename(file), erb) }
|
74
|
+
end if cfn["Include"]
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
#########################
|
79
|
+
# Call ValidateTemplate[https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_ValidateTemplate.html]
|
80
|
+
def validate
|
81
|
+
require "aws-sdk-cloudformation"
|
82
|
+
Aws::CloudFormation::Client.new.validate_template({ template_body: pp })
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
#########################
|
87
|
+
# Format contents
|
88
|
+
def pp
|
89
|
+
case @format
|
90
|
+
when "json"
|
91
|
+
to_hash.to_json
|
92
|
+
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}", "!")
|
96
|
+
else
|
97
|
+
to_hash
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
#########################
|
104
|
+
# Create a hash of each populated section's contents
|
105
|
+
def to_hash
|
106
|
+
h = Hash.new
|
107
|
+
@sections.each { |k, v| h[k] = v.contents if v.length > 0 }
|
108
|
+
h
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
#########################
|
113
|
+
# Read file and (optionally) perform ERB processing on it
|
114
|
+
def load(file, erb = true)
|
115
|
+
path = File.expand_path(file)
|
116
|
+
raise KeyError if @parsed.has_key?(path)
|
117
|
+
|
118
|
+
$logger.info { "Loading #{file}" } if $logger
|
119
|
+
|
120
|
+
contents = File.read(file)
|
121
|
+
contents = ERB.new(contents).result(@binding) if erb
|
122
|
+
|
123
|
+
@parsed[path] = true
|
124
|
+
|
125
|
+
return contents
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
#########################
|
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 = [
|
144
|
+
"Base64",
|
145
|
+
"Cidr",
|
146
|
+
"FindInMap",
|
147
|
+
"GetAtt",
|
148
|
+
"GetAZs",
|
149
|
+
"ImportValue",
|
150
|
+
"Join",
|
151
|
+
"Ref",
|
152
|
+
"Select",
|
153
|
+
"Split",
|
154
|
+
"Transform",
|
155
|
+
"And",
|
156
|
+
"Equals",
|
157
|
+
"If",
|
158
|
+
"Not",
|
159
|
+
"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
|
+
"Sub",
|
170
|
+
].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
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
data/mkstack.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "mkstack"
|
3
|
+
s.version = "1.0.0"
|
4
|
+
s.summary = "Merge multiple CloudFormation template files into a single template"
|
5
|
+
s.description = <<-EOF
|
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.
|
7
|
+
EOF
|
8
|
+
|
9
|
+
s.authors = [ "Andy Rosen" ]
|
10
|
+
s.email = [ "ajr@corp.mlfs.org" ]
|
11
|
+
s.homepage = "https://github.com/ajrosen/AWS/tree/master/mkstack"
|
12
|
+
s.licenses = [ "GPL-3.0+" ]
|
13
|
+
|
14
|
+
s.files = Dir[ "mkstack.gemspec", "bin/*", "lib/**/*.rb" ]
|
15
|
+
s.executables = [ "mkstack" ]
|
16
|
+
|
17
|
+
s.add_runtime_dependency "aws-sdk-cloudformation", "~> 1"
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mkstack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andy Rosen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIEOjCCAqKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBphanIv
|
14
|
+
REM9Y29ycC9EQz1tbGZzL0RDPW9yZzAeFw0xOTA1MDEwMjIwNTBaFw0yMDA0MzAw
|
15
|
+
MjIwNTBaMCUxIzAhBgNVBAMMGmFqci9EQz1jb3JwL0RDPW1sZnMvREM9b3JnMIIB
|
16
|
+
ojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAqQ2xCUJ4wY8WujSzYd3OGTbj
|
17
|
+
JDMeU44pXOTLc49Rs8ydukGfd0YBvYMzifmiVRj6depGx2+Ln28Y2mT6IB+zHq8X
|
18
|
+
s1lrMdFCReztJjQ7OYS16YcZ6pmLkYClnHN3VNqayk1lQEJGCr8aawMeroSB01om
|
19
|
+
d5wqDATnKEG3x4bnlxFJb3LHzUG1CgNuVCuNREi8zN/uYdm2MGe1fTJguy4/vzBQ
|
20
|
+
/FnAMt1mr3LtM6YZRGaitIlOKBV/08v7fjH31KRmSMMHPq6A+WyWKRNKnK3tHpSN
|
21
|
+
JbnFW7mFQGtBpfh8zY8OCQ76Aw8cb5bEIPTI+Hd4FoJLPKnexTI28endSLigOUCF
|
22
|
+
76kLOiVOVOjdqZ8vEdSgWVugEAzIC30xW5b8yD6N7GdT7n3ktgoZu7jZMUW3D6PQ
|
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
|
36
|
+
-----END CERTIFICATE-----
|
37
|
+
date: 2019-05-02 00:00:00.000000000 Z
|
38
|
+
dependencies:
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: aws-sdk-cloudformation
|
41
|
+
requirement: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - "~>"
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1'
|
46
|
+
type: :runtime
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - "~>"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '1'
|
53
|
+
description: 'Merge multiple CloudFormation template files into a single template. Each
|
54
|
+
file may be in either JSON or YAML format. By default all files are run through
|
55
|
+
an ERB (Embedded RuBy) processor.
|
56
|
+
|
57
|
+
'
|
58
|
+
email:
|
59
|
+
- ajr@corp.mlfs.org
|
60
|
+
executables:
|
61
|
+
- mkstack
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- bin/mkstack
|
66
|
+
- lib/mkstack.rb
|
67
|
+
- lib/mkstack/section.rb
|
68
|
+
- lib/mkstack/template.rb
|
69
|
+
- mkstack.gemspec
|
70
|
+
homepage: https://github.com/ajrosen/AWS/tree/master/mkstack
|
71
|
+
licenses:
|
72
|
+
- GPL-3.0+
|
73
|
+
metadata: {}
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 2.7.6
|
91
|
+
signing_key:
|
92
|
+
specification_version: 4
|
93
|
+
summary: Merge multiple CloudFormation template files into a single template
|
94
|
+
test_files: []
|
metadata.gz.sig
ADDED
Binary file
|