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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.cody/demo.rb +21 -21
  3. data/CHANGELOG.md +14 -0
  4. data/lib/lono.rb +1 -1
  5. data/lib/lono/blueprint/meta.rb +38 -0
  6. data/lib/lono/cfn/base.rb +19 -12
  7. data/lib/lono/cfn/delete.rb +2 -1
  8. data/lib/lono/cfn/preview/changeset.rb +14 -1
  9. data/lib/lono/cfn/rollback.rb +1 -1
  10. data/lib/lono/cfn/status.rb +1 -1
  11. data/lib/lono/help/blueprint.md +35 -24
  12. data/lib/lono/help/param.md +4 -1
  13. data/lib/lono/help/seed.md +13 -6
  14. data/lib/lono/help/summary.md +22 -8
  15. data/lib/lono/inspector/summary.rb +4 -3
  16. data/lib/lono/output_template.rb +2 -2
  17. data/lib/lono/s3/bucket.rb +1 -1
  18. data/lib/lono/seed/base.rb +1 -0
  19. data/lib/lono/seed/service_role.rb +11 -0
  20. data/lib/lono/template/dsl/builder.rb +3 -7
  21. data/lib/lono/template/dsl/builder/base.rb +24 -3
  22. data/lib/lono/template/dsl/builder/fn.rb +15 -11
  23. data/lib/lono/template/dsl/builder/{helper.rb → helpers.rb} +5 -4
  24. data/lib/lono/template/dsl/builder/helpers/param_helper.rb +33 -0
  25. data/lib/lono/template/dsl/builder/output.rb +4 -4
  26. data/lib/lono/template/dsl/builder/parameter.rb +2 -2
  27. data/lib/lono/template/dsl/builder/resource.rb +4 -3
  28. data/lib/lono/template/dsl/builder/resource/property_mover.rb +4 -0
  29. data/lib/lono/template/dsl/builder/syntax.rb +6 -7
  30. data/lib/lono/version.rb +1 -1
  31. data/lib/templates/blueprint/%blueprint_name%.gemspec.tt +1 -1
  32. data/lib/templates/blueprint/.meta/config.yml.tt +2 -1
  33. data/lib/templates/blueprint/README.md +1 -1
  34. data/lib/templates/blueprint_types/dsl/app/templates/%blueprint_name%.rb +22 -22
  35. data/lib/templates/skeleton/README.md +1 -1
  36. data/lono.gemspec +1 -1
  37. data/vendor/cfn-status/CHANGELOG.md +4 -0
  38. data/vendor/cfn-status/README.md +4 -2
  39. data/vendor/cfn-status/bin/console +1 -1
  40. data/vendor/cfn-status/cfn-status.gemspec +2 -2
  41. data/vendor/cfn-status/lib/cfn-status.rb +1 -1
  42. data/vendor/cfn-status/lib/cfn_status.rb +245 -0
  43. data/vendor/cfn-status/lib/{cfn → cfn_status}/aws_service.rb +1 -1
  44. data/vendor/cfn-status/lib/cfn_status/version.rb +3 -0
  45. data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-1.json +1103 -0
  46. data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-2.json +1104 -0
  47. data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-3.json +1103 -0
  48. data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-1.json +1103 -0
  49. data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-2.json +1104 -0
  50. data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-3.json +1103 -0
  51. data/vendor/cfn-status/spec/lib/cfn_status_spec.rb +153 -0
  52. data/vendor/cfn-status/spec/spec_helper.rb +1 -1
  53. metadata +17 -8
  54. data/vendor/cfn-status/lib/cfn/status.rb +0 -219
  55. data/vendor/cfn-status/lib/cfn/status/version.rb +0 -5
  56. data/vendor/cfn-status/spec/cfn/status_spec.rb +0 -81
@@ -103,7 +103,7 @@ class Lono::S3
103
103
  end
104
104
 
105
105
  def status
106
- ::Cfn::Status.new(STACK_NAME)
106
+ CfnStatus.new(STACK_NAME)
107
107
  end
108
108
  memoize :status
109
109
 
@@ -16,6 +16,7 @@ class Lono::Seed
16
16
  include Lono::Blueprint::Root
17
17
  include Lono::AwsServices
18
18
  include Lono::Conventions
19
+ include ServiceRole
19
20
 
20
21
  # What's needed for a Thor::Group or "Sequence"
21
22
  # Gives us Thor::Actions commands like create_file
@@ -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 Helper # built-in helpers
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
- camelize(@cfn)
30
+ @cfn
31
31
  end
32
32
  memoize :template
33
33
 
34
34
  def build_template
35
- @results = YAML.dump(camelize(@cfn))
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 Helper
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
- CfnCamelizer.transform(attributes)
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 , we'll use fn_if instead
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
- define_method(name) do |arg|
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
- define_method(name) do |*args|
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::#{CfnCamelizer.camelize(name)}"
66
+ "Fn::#{name.to_s.camelize}"
65
67
  end
66
68
 
67
69
  # special cases
68
70
  def ref(name)
69
- name = CfnCamelizer.camelize(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
- { "Fn::GetAtt" => list }
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 Helper
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
- CfnCamelizer.camelize(k)
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
- {key: k, value: v}
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[:name] = h.delete(:key)
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 = {value: second}
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) ? { value: second } : {}
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 = {value: ref(logical_id) }
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) ? { default: 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[:type] ||= 'String'
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].nil? || attributes[:properties].empty?
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
- type: type
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[:properties] = properties unless properties.empty?
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
@@ -1,3 +1,3 @@
1
1
  module Lono
2
- VERSION = "5.3.4"
2
+ VERSION = "6.0.0"
3
3
  end
@@ -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/user/repo" # TODO: Change me
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'
@@ -1,3 +1,4 @@
1
1
  ---
2
2
  blueprint_name: <%= blueprint_name %>
3
- template_type: dsl
3
+ template_type: dsl
4
+ auto_camelize: false
@@ -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 --blueprint BLUEPRINT --iam
37
+ LONO_ENV=production lono cfn deploy BLUEPRINT-production --blueprint BLUEPRINT --iam
@@ -1,36 +1,36 @@
1
- # Simple Starter Demo Example
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": { 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" }
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
- instance_type: ref("InstanceType"),
28
- image_id: find_in_map("AmiMap", ref("AWS::Region"), :ami),
29
- security_group_ids: [get_att("SecurityGroup.GroupId")],
30
- user_data: base64(user_data("bootstrap.sh"))
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
- group_description: "demo security group",
33
+ GroupDescription: "demo security group",
34
34
  )
35
35
 
36
36
  output("Instance")