lono 5.3.4 → 6.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 +4 -4
- data/.cody/demo.rb +21 -21
- data/CHANGELOG.md +14 -0
- data/lib/lono.rb +1 -1
- data/lib/lono/blueprint/meta.rb +38 -0
- data/lib/lono/cfn/base.rb +19 -12
- data/lib/lono/cfn/delete.rb +2 -1
- data/lib/lono/cfn/preview/changeset.rb +14 -1
- data/lib/lono/cfn/rollback.rb +1 -1
- data/lib/lono/cfn/status.rb +1 -1
- data/lib/lono/help/blueprint.md +35 -24
- data/lib/lono/help/param.md +4 -1
- data/lib/lono/help/seed.md +13 -6
- data/lib/lono/help/summary.md +22 -8
- data/lib/lono/inspector/summary.rb +4 -3
- data/lib/lono/output_template.rb +2 -2
- data/lib/lono/s3/bucket.rb +1 -1
- data/lib/lono/seed/base.rb +1 -0
- data/lib/lono/seed/service_role.rb +11 -0
- data/lib/lono/template/dsl/builder.rb +3 -7
- data/lib/lono/template/dsl/builder/base.rb +24 -3
- data/lib/lono/template/dsl/builder/fn.rb +15 -11
- data/lib/lono/template/dsl/builder/{helper.rb → helpers.rb} +5 -4
- data/lib/lono/template/dsl/builder/helpers/param_helper.rb +33 -0
- data/lib/lono/template/dsl/builder/output.rb +4 -4
- data/lib/lono/template/dsl/builder/parameter.rb +2 -2
- data/lib/lono/template/dsl/builder/resource.rb +4 -3
- data/lib/lono/template/dsl/builder/resource/property_mover.rb +4 -0
- data/lib/lono/template/dsl/builder/syntax.rb +6 -7
- data/lib/lono/version.rb +1 -1
- data/lib/templates/blueprint/%blueprint_name%.gemspec.tt +1 -1
- data/lib/templates/blueprint/.meta/config.yml.tt +2 -1
- data/lib/templates/blueprint/README.md +1 -1
- data/lib/templates/blueprint_types/dsl/app/templates/%blueprint_name%.rb +22 -22
- data/lib/templates/skeleton/README.md +1 -1
- data/lono.gemspec +1 -1
- data/vendor/cfn-status/CHANGELOG.md +4 -0
- data/vendor/cfn-status/README.md +4 -2
- data/vendor/cfn-status/bin/console +1 -1
- data/vendor/cfn-status/cfn-status.gemspec +2 -2
- data/vendor/cfn-status/lib/cfn-status.rb +1 -1
- data/vendor/cfn-status/lib/cfn_status.rb +245 -0
- data/vendor/cfn-status/lib/{cfn → cfn_status}/aws_service.rb +1 -1
- data/vendor/cfn-status/lib/cfn_status/version.rb +3 -0
- data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-1.json +1103 -0
- data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-2.json +1104 -0
- data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-3.json +1103 -0
- data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-1.json +1103 -0
- data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-2.json +1104 -0
- data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-3.json +1103 -0
- data/vendor/cfn-status/spec/lib/cfn_status_spec.rb +153 -0
- data/vendor/cfn-status/spec/spec_helper.rb +1 -1
- metadata +17 -8
- data/vendor/cfn-status/lib/cfn/status.rb +0 -219
- data/vendor/cfn-status/lib/cfn/status/version.rb +0 -5
- data/vendor/cfn-status/spec/cfn/status_spec.rb +0 -81
data/lib/lono/s3/bucket.rb
CHANGED
data/lib/lono/seed/base.rb
CHANGED
@@ -0,0 +1,11 @@
|
|
1
|
+
class Lono::Seed
|
2
|
+
module ServiceRole
|
3
|
+
def create_service_linked_role(aws_service_name)
|
4
|
+
iam.create_service_linked_role(
|
5
|
+
aws_service_name: aws_service_name
|
6
|
+
)
|
7
|
+
rescue Aws::IAM::Errors::InvalidInput # already exist
|
8
|
+
raise if ENV['LONO_DEBUG_SEED']
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -4,7 +4,7 @@ class Lono::Template::Dsl
|
|
4
4
|
include Lono::Template::Context::Loader
|
5
5
|
|
6
6
|
include Fn
|
7
|
-
include
|
7
|
+
include Helpers # built-in helpers
|
8
8
|
include Lono::Template::Evaluate
|
9
9
|
include Syntax
|
10
10
|
extend Memoist
|
@@ -27,12 +27,12 @@ class Lono::Template::Dsl
|
|
27
27
|
def template
|
28
28
|
load_context
|
29
29
|
evaluate_template_path(@path) # modifies @cfn
|
30
|
-
|
30
|
+
@cfn
|
31
31
|
end
|
32
32
|
memoize :template
|
33
33
|
|
34
34
|
def build_template
|
35
|
-
@results = YAML.dump(
|
35
|
+
@results = YAML.dump(@cfn)
|
36
36
|
end
|
37
37
|
|
38
38
|
def write_output
|
@@ -51,10 +51,6 @@ class Lono::Template::Dsl
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
def camelize(data)
|
55
|
-
CfnCamelizer.transform(data)
|
56
|
-
end
|
57
|
-
|
58
54
|
# Not using Lono::Template::Context because that works differently.
|
59
55
|
# That is used to load a context object that is passed to RenderMePretty's context.
|
60
56
|
# So that we can load context for params files and erb templates.
|
@@ -1,14 +1,35 @@
|
|
1
1
|
class Lono::Template::Dsl::Builder
|
2
2
|
class Base
|
3
3
|
include Fn
|
4
|
-
include
|
4
|
+
include Helpers
|
5
5
|
|
6
|
-
def initialize(*definition)
|
6
|
+
def initialize(blueprint, *definition)
|
7
|
+
@blueprint = blueprint
|
7
8
|
@definition = definition.flatten
|
8
9
|
end
|
9
10
|
|
11
|
+
private
|
10
12
|
def camelize(attributes)
|
11
|
-
|
13
|
+
blueprint_meta = Lono::Blueprint::Meta.new(@blueprint)
|
14
|
+
target_section = self.class.to_s.split('::').last.underscore
|
15
|
+
# target_section: Lono::Template::Dsl::Builder::Parameter => parameter
|
16
|
+
if blueprint_meta.auto_camelize?(target_section)
|
17
|
+
CfnCamelizer.transform(attributes)
|
18
|
+
else
|
19
|
+
stringify_keys!(attributes)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Accounts for Arrays also. ActiveSupport only works for Hashes.
|
24
|
+
def stringify_keys!(data)
|
25
|
+
case data
|
26
|
+
when Array
|
27
|
+
data.map! { |i| stringify_keys!(i) }
|
28
|
+
when Hash
|
29
|
+
data.deep_transform_keys! { |k| k.to_s }
|
30
|
+
else
|
31
|
+
data # do not transform
|
32
|
+
end
|
12
33
|
end
|
13
34
|
end
|
14
35
|
end
|
@@ -21,7 +21,7 @@ class Lono::Template::Dsl::Builder
|
|
21
21
|
# so they can also be called via fn::if
|
22
22
|
and: :array,
|
23
23
|
equals: :array,
|
24
|
-
if: :array, # special case, if is a Ruby keyword
|
24
|
+
if: :array, # special case, if is a Ruby keyword
|
25
25
|
not: :array,
|
26
26
|
or: :array,
|
27
27
|
ref: :simple,
|
@@ -29,6 +29,12 @@ class Lono::Template::Dsl::Builder
|
|
29
29
|
# These are also Ruby keywords
|
30
30
|
# keywords: and if not or
|
31
31
|
|
32
|
+
# Defines both normal method and bang method. Example: if and if!
|
33
|
+
def self.define_methods(name, &block)
|
34
|
+
define_method(name, &block)
|
35
|
+
define_method("#{name}!", &block)
|
36
|
+
end
|
37
|
+
|
32
38
|
# Note, for if function, do not flatten the args. Its arguments can be Arrays. Example:
|
33
39
|
#
|
34
40
|
# SecurityGroups:
|
@@ -42,31 +48,27 @@ class Lono::Template::Dsl::Builder
|
|
42
48
|
# Ref: ExistingSecurityGroup
|
43
49
|
FUNCTIONS.each do |name, type|
|
44
50
|
if type == :simple
|
45
|
-
|
51
|
+
define_methods(name) do |arg|
|
46
52
|
id = fn_id(name)
|
47
|
-
arg = arg.is_a?(Symbol) ? CfnCamelizer.camelize(arg) : arg
|
48
53
|
{ id => arg }
|
49
54
|
end
|
50
55
|
else # array
|
51
|
-
|
56
|
+
define_methods(name) do |*args|
|
52
57
|
id = fn_id(name)
|
53
58
|
# Note, do not flatten args for if statement as it can have Array as arguments.
|
54
59
|
args = args.flatten unless name == :if
|
55
|
-
args = args.map do |arg|
|
56
|
-
arg.is_a?(Symbol) ? CfnCamelizer.camelize(arg) : arg
|
57
|
-
end
|
58
60
|
{ id => args }
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
63
65
|
def fn_id(name)
|
64
|
-
"Fn::#{
|
66
|
+
"Fn::#{name.to_s.camelize}"
|
65
67
|
end
|
66
68
|
|
67
69
|
# special cases
|
68
70
|
def ref(name)
|
69
|
-
name =
|
71
|
+
name = name.to_s.camelize
|
70
72
|
{ "Ref" => name }
|
71
73
|
end
|
72
74
|
|
@@ -84,8 +86,10 @@ class Lono::Template::Dsl::Builder
|
|
84
86
|
else
|
85
87
|
item
|
86
88
|
end
|
87
|
-
list.map!(&:camelize) unless options[:autoformat] == false
|
88
|
-
|
89
|
+
# list.map!(&:camelize) unless options[:autoformat] == false # TODO: maybe add as an option.
|
90
|
+
# feel this may be to destructive since am going with auto_camelize false for resources now.
|
91
|
+
args = [list[0], list[1..-1].join('.')]
|
92
|
+
{ "Fn::GetAtt" => args }
|
89
93
|
end
|
90
94
|
|
91
95
|
def join(delimiter, *list)
|
@@ -1,14 +1,15 @@
|
|
1
1
|
# Built-in helpers for the DSL form
|
2
2
|
class Lono::Template::Dsl::Builder
|
3
|
-
module
|
3
|
+
module Helpers
|
4
4
|
extend Memoist
|
5
|
+
include ParamHelper
|
5
6
|
|
6
7
|
def tags(hash, casing: :camelize)
|
7
8
|
hash.map do |k,v|
|
8
9
|
k = k.to_s
|
9
10
|
k = case casing
|
10
11
|
when :camelize
|
11
|
-
|
12
|
+
k.camelize
|
12
13
|
when :underscore
|
13
14
|
k.underscore
|
14
15
|
when :dasherize
|
@@ -17,13 +18,13 @@ class Lono::Template::Dsl::Builder
|
|
17
18
|
k
|
18
19
|
end
|
19
20
|
|
20
|
-
{
|
21
|
+
{Key: k, Value: v}
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
25
|
def dimensions(hash, casing: :camelize)
|
25
26
|
tags(hash, casing: casing).map { |h|
|
26
|
-
h[:
|
27
|
+
h[:Name] = h.delete(:Key) || h.delete(:key)
|
27
28
|
h
|
28
29
|
}
|
29
30
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Note: These are experimental helpers. Their interface may change or removed entirely.
|
2
|
+
module Lono::Template::Dsl::Builder::Helpers
|
3
|
+
module ParamHelper
|
4
|
+
# Creates:
|
5
|
+
#
|
6
|
+
# 1. parameter
|
7
|
+
# 2. condition - used to make it optional
|
8
|
+
#
|
9
|
+
def conditional_parameter(name, options={})
|
10
|
+
options = normalize_conditional_parameter_options(options)
|
11
|
+
parameter(name, options)
|
12
|
+
condition("Has#{name}", not!(equals(ref(name), "")))
|
13
|
+
end
|
14
|
+
|
15
|
+
# use long name to minimize method name collision
|
16
|
+
def normalize_conditional_parameter_options(options)
|
17
|
+
if options.is_a?(Hash)
|
18
|
+
options = if options.empty?
|
19
|
+
""
|
20
|
+
else
|
21
|
+
defaults = { Default: "" }
|
22
|
+
options.reverse_merge(defaults)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
options
|
27
|
+
end
|
28
|
+
|
29
|
+
def optional_ref(name)
|
30
|
+
if!("Has#{name}", ref(name), ref("AWS::NoValue"))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -14,20 +14,20 @@ class Lono::Template::Dsl::Builder
|
|
14
14
|
if definition.size == 1 && first.is_a?(Hash) # long form
|
15
15
|
first # pass through
|
16
16
|
elsif definition.size == 2 && second.is_a?(Hash) # medium form
|
17
|
-
if second.key?(:value)
|
17
|
+
if second.key?(:value) || second.key?("Value")
|
18
18
|
logical_id, properties = first, second
|
19
19
|
else
|
20
20
|
logical_id = first
|
21
|
-
properties = {
|
21
|
+
properties = {Value: second}
|
22
22
|
end
|
23
23
|
{ logical_id => properties }
|
24
24
|
elsif definition.size == 2 && (second.is_a?(String) || second.nil?) # short form
|
25
25
|
logical_id = first
|
26
|
-
properties = second.is_a?(String) ? {
|
26
|
+
properties = second.is_a?(String) ? { Value: second } : {}
|
27
27
|
{ logical_id => properties }
|
28
28
|
elsif definition.size == 1
|
29
29
|
logical_id = first.to_s
|
30
|
-
properties = {
|
30
|
+
properties = { Value: ref(logical_id) }
|
31
31
|
{ logical_id => properties }
|
32
32
|
else # I dont know what form
|
33
33
|
raise "Invalid form provided. definition #{definition.inspect}"
|
@@ -19,7 +19,7 @@ class Lono::Template::Dsl::Builder
|
|
19
19
|
elsif (definition.size == 2 && valid_value?(second)) || # short form
|
20
20
|
definition.size == 1
|
21
21
|
logical_id = first
|
22
|
-
properties = valid_value?(second) ? {
|
22
|
+
properties = valid_value?(second) ? { Default: second } : {}
|
23
23
|
{ logical_id => properties }
|
24
24
|
else # I dont know what form
|
25
25
|
raise "Invalid form provided. definition #{definition.inspect}"
|
@@ -28,7 +28,7 @@ class Lono::Template::Dsl::Builder
|
|
28
28
|
|
29
29
|
def add_required(attributes)
|
30
30
|
properties = attributes.values.first
|
31
|
-
properties[
|
31
|
+
properties["Type"] ||= 'String'
|
32
32
|
attributes
|
33
33
|
end
|
34
34
|
|
@@ -15,7 +15,8 @@ class Lono::Template::Dsl::Builder
|
|
15
15
|
first # pass through
|
16
16
|
elsif definition.size == 2 && second.is_a?(Hash) # medium form
|
17
17
|
logical_id, attributes = first, second
|
18
|
-
attributes.delete(:properties) if attributes[:properties].
|
18
|
+
attributes.delete(:properties) if attributes[:properties].blank?
|
19
|
+
attributes.delete("Properties") if attributes["Properties"].blank?
|
19
20
|
{ logical_id => attributes }
|
20
21
|
elsif definition.size == 2 && second.is_a?(String) # short form with no properties
|
21
22
|
logical_id, type = first, second
|
@@ -25,7 +26,7 @@ class Lono::Template::Dsl::Builder
|
|
25
26
|
elsif definition.size == 3 && (second.is_a?(String) || second.is_a?(NilClass)) # short form
|
26
27
|
logical_id, type, properties = first, second, third
|
27
28
|
resource = { logical_id => {
|
28
|
-
|
29
|
+
Type: type
|
29
30
|
}}
|
30
31
|
|
31
32
|
attributes = resource.values.first
|
@@ -33,7 +34,7 @@ class Lono::Template::Dsl::Builder
|
|
33
34
|
property_mover = PropertyMover.new(resource, logical_id, properties)
|
34
35
|
property_mover.move!
|
35
36
|
|
36
|
-
attributes[
|
37
|
+
attributes["Properties"] = properties unless properties.empty?
|
37
38
|
resource
|
38
39
|
else # Dont understand this form
|
39
40
|
raise "Invalid form provided. definition #{definition.inspect}"
|
@@ -7,7 +7,11 @@ class Lono::Template::Dsl::Builder::Resource
|
|
7
7
|
|
8
8
|
def move!
|
9
9
|
%w[depends_on condition].each do |attribute_name|
|
10
|
+
# Account for camelize, underscore, String, and Symbol
|
10
11
|
move(attribute_name.to_sym)
|
12
|
+
move(attribute_name.camelize.to_sym)
|
13
|
+
move(attribute_name)
|
14
|
+
move(attribute_name.camelize)
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
@@ -15,44 +15,43 @@ class Lono::Template::Dsl::Builder
|
|
15
15
|
|
16
16
|
def transform(*definition)
|
17
17
|
definition = definition.flatten
|
18
|
-
definition.map! { |x| CfnCamelizer.camelize(x) }
|
19
18
|
@cfn["Transform"] = definition.size == 1 ? definition.first : definition
|
20
19
|
end
|
21
20
|
|
22
21
|
def parameter(*definition)
|
23
22
|
@cfn["Parameters"] ||= {}
|
24
|
-
param = Parameter.new(definition)
|
23
|
+
param = Parameter.new(@blueprint, definition)
|
25
24
|
@cfn["Parameters"].merge!(param.template)
|
26
25
|
end
|
27
26
|
|
28
27
|
def mapping(*definition)
|
29
28
|
@cfn["Mappings"] ||= {}
|
30
|
-
mapping = Mapping.new(definition)
|
29
|
+
mapping = Mapping.new(@blueprint, definition)
|
31
30
|
@cfn["Mappings"].merge!(mapping.template)
|
32
31
|
end
|
33
32
|
|
34
33
|
def resource(*definition)
|
35
34
|
@cfn["Resources"] ||= {}
|
36
|
-
resource = Resource.new(definition)
|
35
|
+
resource = Resource.new(@blueprint, definition)
|
37
36
|
@cfn["Resources"].merge!(resource.template)
|
38
37
|
end
|
39
38
|
|
40
39
|
def condition(*definition)
|
41
40
|
@cfn["Conditions"] ||= {}
|
42
|
-
condition = Condition.new(definition)
|
41
|
+
condition = Condition.new(@blueprint, definition)
|
43
42
|
@cfn["Conditions"].merge!(condition.template)
|
44
43
|
end
|
45
44
|
|
46
45
|
def output(*definition)
|
47
46
|
@cfn["Outputs"] ||= {}
|
48
|
-
output = Output.new(definition)
|
47
|
+
output = Output.new(@blueprint, definition)
|
49
48
|
@cfn["Outputs"].merge!(output.template)
|
50
49
|
end
|
51
50
|
|
52
51
|
# Generic section method in case CloudFormation adds a new future section.
|
53
52
|
# The generic section method adds a new top-level key
|
54
53
|
def section(key, definition)
|
55
|
-
@cfn[key] = Section.new(definition).template
|
54
|
+
@cfn[key] = Section.new(@blueprint, definition).template
|
56
55
|
end
|
57
56
|
end
|
58
57
|
end
|
data/lib/lono/version.rb
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
|
10
10
|
spec.summary = "Write a short summary because it's required." # TODO: Change me
|
11
11
|
spec.description = "Write a longer description or delete this line." # TODO: Change me
|
12
|
-
spec.homepage = "https://github.com/
|
12
|
+
spec.homepage = "https://github.com/USER/<%= blueprint_name %>" # TODO: Change me
|
13
13
|
spec.license = "<%= ENV['LONO_LICENSE'] || 'MIT' %>"
|
14
14
|
|
15
15
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
@@ -34,4 +34,4 @@ The PARAM depends on how the blueprint was authored. The PARAM conventionally d
|
|
34
34
|
Use the [lono cfn deploy](http://lono.cloud/reference/lono-cfn-deploy/) command to deploy. Example:
|
35
35
|
|
36
36
|
LONO_ENV=development lono cfn deploy BLUEPRINT-development --blueprint BLUEPRINT --iam
|
37
|
-
LONO_ENV=production lono cfn deploy BLUEPRINT-production
|
37
|
+
LONO_ENV=production lono cfn deploy BLUEPRINT-production --blueprint BLUEPRINT --iam
|
@@ -1,36 +1,36 @@
|
|
1
|
-
#
|
1
|
+
# Starter Demo Example
|
2
2
|
aws_template_format_version "2010-09-09"
|
3
3
|
description "Demo stack"
|
4
4
|
|
5
5
|
parameter("InstanceType", "t3.micro")
|
6
6
|
|
7
7
|
mapping("AmiMap",
|
8
|
-
"ap-northeast-1": {
|
9
|
-
"ap-northeast-2": {
|
10
|
-
"ap-south-1": {
|
11
|
-
"ap-southeast-1": {
|
12
|
-
"ap-southeast-2": {
|
13
|
-
"ca-central-1": {
|
14
|
-
"eu-central-1": {
|
15
|
-
"eu-north-1": {
|
16
|
-
"eu-west-1": {
|
17
|
-
"eu-west-2": {
|
18
|
-
"eu-west-3": {
|
19
|
-
"sa-east-1": {
|
20
|
-
"us-east-1": {
|
21
|
-
"us-east-2": {
|
22
|
-
"us-west-1": {
|
23
|
-
"us-west-2": {
|
8
|
+
"ap-northeast-1": { Ami: "ami-0f9ae750e8274075b" },
|
9
|
+
"ap-northeast-2": { Ami: "ami-047f7b46bd6dd5d84" },
|
10
|
+
"ap-south-1": { Ami: "ami-0889b8a448de4fc44" },
|
11
|
+
"ap-southeast-1": { Ami: "ami-0b419c3a4b01d1859" },
|
12
|
+
"ap-southeast-2": { Ami: "ami-04481c741a0311bbb" },
|
13
|
+
"ca-central-1": { Ami: "ami-03338e1f67dae0168" },
|
14
|
+
"eu-central-1": { Ami: "ami-09def150731bdbcc2" },
|
15
|
+
"eu-north-1": { Ami: "ami-d16fe6af" },
|
16
|
+
"eu-west-1": { Ami: "ami-07683a44e80cd32c5" },
|
17
|
+
"eu-west-2": { Ami: "ami-09ead922c1dad67e4" },
|
18
|
+
"eu-west-3": { Ami: "ami-0451ae4fd8dd178f7" },
|
19
|
+
"sa-east-1": { Ami: "ami-0669a96e355eac82f" },
|
20
|
+
"us-east-1": { Ami: "ami-0de53d8956e8dcf80" },
|
21
|
+
"us-east-2": { Ami: "ami-02bcbb802e03574ba" },
|
22
|
+
"us-west-1": { Ami: "ami-0019ef04ac50be30f" },
|
23
|
+
"us-west-2": { Ami: "ami-061392db613a6357b" }
|
24
24
|
)
|
25
25
|
|
26
26
|
resource("Instance", "AWS::EC2::Instance",
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
InstanceType: ref("InstanceType"),
|
28
|
+
ImageId: find_in_map("AmiMap", ref("AWS::Region"), "Ami"),
|
29
|
+
SecurityGroupIds: [get_att("SecurityGroup.GroupId")],
|
30
|
+
UserData: base64(user_data("bootstrap.sh"))
|
31
31
|
)
|
32
32
|
resource("SecurityGroup", "AWS::EC2::SecurityGroup",
|
33
|
-
|
33
|
+
GroupDescription: "demo security group",
|
34
34
|
)
|
35
35
|
|
36
36
|
output("Instance")
|