lono 5.3.4 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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")