cfoo 0.0.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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.simplecov +4 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +676 -0
  7. data/README.md +166 -0
  8. data/Rakefile +10 -0
  9. data/TODO +29 -0
  10. data/bin/cfoo +26 -0
  11. data/cfoo.gemspec +35 -0
  12. data/features/attribute_expansion.feature +43 -0
  13. data/features/convert_yaml_to_json.feature +69 -0
  14. data/features/el_escaping.feature +21 -0
  15. data/features/map_reference_expansion.feature +68 -0
  16. data/features/modules.feature +101 -0
  17. data/features/parse_files.feature +46 -0
  18. data/features/reference_expansion.feature +49 -0
  19. data/features/step_definitions/cfoo_steps.rb +107 -0
  20. data/features/support/env.rb +5 -0
  21. data/features/yamly_shortcuts.feature +132 -0
  22. data/lib/cfoo.rb +11 -0
  23. data/lib/cfoo/cfoo.rb +15 -0
  24. data/lib/cfoo/el_parser.rb +105 -0
  25. data/lib/cfoo/file_system.rb +28 -0
  26. data/lib/cfoo/module.rb +25 -0
  27. data/lib/cfoo/parser.rb +82 -0
  28. data/lib/cfoo/processor.rb +38 -0
  29. data/lib/cfoo/project.rb +16 -0
  30. data/lib/cfoo/renderer.rb +9 -0
  31. data/lib/cfoo/version.rb +3 -0
  32. data/lib/cfoo/yaml.rb +34 -0
  33. data/lib/cfoo/yaml_parser.rb +16 -0
  34. data/spec/cfoo/cfoo_spec.rb +31 -0
  35. data/spec/cfoo/el_parser_spec.rb +47 -0
  36. data/spec/cfoo/file_system_spec.rb +61 -0
  37. data/spec/cfoo/module_spec.rb +16 -0
  38. data/spec/cfoo/parser_spec.rb +148 -0
  39. data/spec/cfoo/processor_spec.rb +52 -0
  40. data/spec/cfoo/project_spec.rb +16 -0
  41. data/spec/cfoo/renderer_spec.rb +19 -0
  42. data/spec/cfoo/yaml_parser_spec.rb +79 -0
  43. data/spec/spec_helper.rb +2 -0
  44. metadata +235 -0
@@ -0,0 +1,101 @@
1
+ Feature: Modules
2
+ As a CloudFormation user
3
+ I want to split my templates into logical modules
4
+ So that I can organise them and share them
5
+
6
+ Scenario: Module with a template
7
+ Given I have a project
8
+ And I have a module named "webapp"
9
+ And I have a file "modules/webapp/webapp.yml" containing
10
+ """
11
+ Parameters:
12
+ FrontendSize:
13
+ Type: Integer
14
+ Default: 5
15
+ Resources:
16
+ FrontendFleet:
17
+ Type: AWS::AutoScaling::AutoScalingGroup
18
+ Properties:
19
+ MinSize: 1
20
+ MaxSize: 10
21
+ """
22
+ When I build the project
23
+ Then the output should match JSON
24
+ """
25
+ {
26
+ "AWSTemplateFormatVersion" : "2010-09-09",
27
+ "Parameters" : {
28
+ "FrontendSize" : { "Type" : "Integer", "Default" : 5 }
29
+ },
30
+ "Resources" : {
31
+ "FrontendFleet" : {
32
+ "Type" : "AWS::AutoScaling::AutoScalingGroup",
33
+ "Properties" : {
34
+ "MinSize" : 1,
35
+ "MaxSize" : 10
36
+ }
37
+ }
38
+ }
39
+ }
40
+ """
41
+
42
+ Scenario: Multiple modules get merged
43
+ Given I have a project
44
+ And I have a module named "webapp"
45
+ And I have a file "modules/webapp/webapp.yml" containing
46
+ """
47
+ Parameters:
48
+ FrontendSize:
49
+ Type: Integer
50
+ Default: 5
51
+ Resources:
52
+ FrontendFleet:
53
+ Type: AWS::AutoScaling::AutoScalingGroup
54
+ Properties:
55
+ MinSize: 1
56
+ MaxSize: $(FrontendSize)
57
+ """
58
+ And I have a module named "database"
59
+ And I have a file "modules/database/database.yml" containing
60
+ """
61
+ Parameters:
62
+ DbName:
63
+ Type: String
64
+ Default: My Precious
65
+ Resources:
66
+ MySQLDatabase:
67
+ Type: AWS::RDS::DBInstance
68
+ Properties:
69
+ Engine: MySQL
70
+ DBName: $(DbName)
71
+ MultiAZ: true
72
+ """
73
+ When I build the project
74
+ Then the output should match JSON
75
+ """
76
+ {
77
+ "AWSTemplateFormatVersion" : "2010-09-09",
78
+ "Parameters" : {
79
+ "FrontendSize" : { "Type" : "Integer", "Default" : 5 },
80
+ "DbName" : { "Type" : "String", "Default" : "My Precious" }
81
+ },
82
+ "Resources" : {
83
+ "FrontendFleet" : {
84
+ "Type" : "AWS::AutoScaling::AutoScalingGroup",
85
+ "Properties" : {
86
+ "MinSize" : 1,
87
+ "MaxSize" : { "Ref" : "FrontendSize" }
88
+ }
89
+ },
90
+ "MySQLDatabase": {
91
+ "Type": "AWS::RDS::DBInstance",
92
+ "Properties": {
93
+ "Engine" : "MySQL",
94
+ "DBName" : { "Ref": "DbName" },
95
+ "MultiAZ" : "true"
96
+ }
97
+ }
98
+ }
99
+ }
100
+ """
101
+
@@ -0,0 +1,46 @@
1
+ Feature: Modules
2
+ As a casual Cfoo user
3
+ I want to combine arbitrary Cfoo templates
4
+ So that I can quickly generate a CloudFormation template without a project structure
5
+
6
+ Scenario: Parse files
7
+ Given I have a file "webapp.yml" containing
8
+ """
9
+ Resources:
10
+ FrontendFleet:
11
+ Type: AWS::AutoScaling::AutoScalingGroup
12
+ Properties:
13
+ MinSize: 1
14
+ MaxSize: 10
15
+ """
16
+ And I have a file "vpc.yml" containing
17
+ """
18
+ Resources:
19
+ VPC:
20
+ Type: AWS::EC2::VPC
21
+ Properties:
22
+ CidrBlock: "10.0.0.0/16"
23
+ """
24
+ When I process files "webapp.yml" and "vpc.yml"
25
+ Then the output should match JSON
26
+ """
27
+ {
28
+ "AWSTemplateFormatVersion" : "2010-09-09",
29
+ "Resources" : {
30
+ "FrontendFleet" : {
31
+ "Type" : "AWS::AutoScaling::AutoScalingGroup",
32
+ "Properties" : {
33
+ "MinSize" : 1,
34
+ "MaxSize" : 10
35
+ }
36
+ },
37
+ "VPC" : {
38
+ "Type" : "AWS::EC2::VPC",
39
+ "Properties" : {
40
+ "CidrBlock" : "10.0.0.0/16"
41
+ }
42
+ }
43
+ }
44
+ }
45
+ """
46
+
@@ -0,0 +1,49 @@
1
+ Feature: Expand EL References
2
+ As a CloudFormation user
3
+ I want to use an expression language as a shorthand for references
4
+ So that I my templates are easier to read
5
+
6
+ Scenario: Simple reference
7
+ Given I have a file "reference.yml" containing
8
+ """
9
+ Server:
10
+ InstanceType: $(InstanceType)
11
+ SecurityGroups:
12
+ - sg-123456
13
+ - $(SshSecurityGroup)
14
+ - sg-987654
15
+ """
16
+ When I process "reference.yml"
17
+ Then the output should match JSON
18
+ """
19
+ {
20
+ "AWSTemplateFormatVersion" : "2010-09-09",
21
+ "Server" : {
22
+ "InstanceType" : { "Ref" : "InstanceType" },
23
+ "SecurityGroups" : [
24
+ "sg-123456",
25
+ { "Ref": "SshSecurityGroup" },
26
+ "sg-987654"
27
+ ]
28
+ }
29
+ }
30
+ """
31
+
32
+ Scenario: Embedded reference
33
+ Given I have a file "reference.yml" containing
34
+ """
35
+ content:
36
+ /var/www/html: http://$(DownloadHost)/website.tar.gz
37
+ /etc/puppet: https://github.com/$(GithubAccount)/$(RepoName).git
38
+ """
39
+ When I process "reference.yml"
40
+ Then the output should match JSON
41
+ """
42
+ {
43
+ "AWSTemplateFormatVersion" : "2010-09-09",
44
+ "content": {
45
+ "/var/www/html" : { "Fn::Join" : [ "", [ "http://", {"Ref" : "DownloadHost"}, "/website.tar.gz" ] ] },
46
+ "/etc/puppet" : { "Fn::Join" : [ "", [ "https://github.com/", {"Ref" : "GithubAccount"}, "/", {"Ref" : "RepoName"}, ".git" ] ] }
47
+ }
48
+ }
49
+ """
@@ -0,0 +1,107 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ include FileUtils
4
+
5
+ Given /^I have a project$/ do
6
+ end
7
+
8
+ Given /^I have a module named "(.*?)"$/ do |module_name|
9
+ create_dir "modules/#{module_name}"
10
+ end
11
+
12
+ Given /^I have a file "(.*?)" containing$/ do |filename, content|
13
+ write_file(filename, content)
14
+ end
15
+
16
+ When /^I process "(.*?)"$/ do |filename|
17
+ cfoo.process(filename)
18
+ end
19
+
20
+ #TODO: can we use varargs?
21
+ When /^I process files "(.*?)"(?:(?:,| and) "(.*?)")$/ do |filename_1, filename_2|
22
+ cfoo.process(filename_1, filename_2)
23
+ end
24
+
25
+ When /^I build the project$/ do
26
+ cfoo.build_project
27
+ end
28
+
29
+ Then(/^the output should match JSON$/) do |expected_json|
30
+ begin
31
+ expected = JSON.parse(expected_json)
32
+ rescue StandardError => e
33
+ puts "Couldn't parse expected ouput as JSON"
34
+ raise e
35
+ end
36
+ begin
37
+ actual = JSON.parse(stdout.messages.join "")
38
+ rescue StandardError => e
39
+ puts "Couldn't parse actual ouput as JSON"
40
+ raise e
41
+ end
42
+ actual.should == expected
43
+ end
44
+
45
+ def write_file(filename, content)
46
+ file_fqn = resolve_file(filename)
47
+ mkdir_p(File.dirname file_fqn)
48
+ File.open(file_fqn, "w") do |file|
49
+ file.puts content
50
+ end
51
+ end
52
+
53
+ def create_dir(directory)
54
+ mkdir_p(resolve_file(directory))
55
+ end
56
+
57
+ def resolve_file(filename)
58
+ "#{project_root}/#{filename}"
59
+ end
60
+
61
+ def cfoo
62
+ @cfoo ||= Cfoo::Cfoo.new(processor, renderer, stdout)
63
+ end
64
+
65
+ def processor
66
+ @processor ||= Cfoo::Processor.new(parser, project)
67
+ end
68
+
69
+ def parser
70
+ @parser ||= Cfoo::Parser.new(file_system)
71
+ end
72
+
73
+ def renderer
74
+ @renderer ||= Cfoo::Renderer.new
75
+ end
76
+
77
+ def project
78
+ @project ||= Cfoo::Project.new(file_system)
79
+ end
80
+
81
+ def file_system
82
+ @file_system ||= Cfoo::FileSystem.new(project_root, Cfoo::YamlParser.new)
83
+ end
84
+
85
+ def project_root
86
+ @project_root ||= "/tmp/cfoo-cucumber-#{$$}"
87
+ mkdir_p(@project_root)
88
+ @project_root
89
+ end
90
+
91
+ def stdout
92
+ @output ||= Output.new
93
+ end
94
+
95
+ After do
96
+ rm_rf project_root if File.directory? project_root
97
+ end
98
+
99
+ class Output
100
+ def messages
101
+ @messages ||= []
102
+ end
103
+
104
+ def puts(message)
105
+ messages << message
106
+ end
107
+ end
@@ -0,0 +1,5 @@
1
+ lib_path = File.expand_path('../../../lib', __FILE__)
2
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include? lib_path
3
+
4
+ require 'simplecov'
5
+ require 'cfoo'
@@ -0,0 +1,132 @@
1
+ Feature: YAMLy shortcuts
2
+ I should be able to write standalone (non-embedded) CloudFormation bits using custom YAML datatypes
3
+ So that I can have a quick YAMLy way to write them
4
+
5
+ Scenario: Reference
6
+ Given I have a file "ref.yml" containing
7
+ """
8
+ Reference: !Ref AWS::Region
9
+ """
10
+ When I process "ref.yml"
11
+ Then the output should match JSON
12
+ """
13
+ {
14
+ "AWSTemplateFormatVersion" : "2010-09-09",
15
+ "Reference" : { "Ref" : "AWS::Region" }
16
+ }
17
+ """
18
+
19
+ Scenario: Attribute
20
+ Given I have a file "ref.yml" containing
21
+ """
22
+ Attribute: !GetAtt [ BastionHost, PublicIp ]
23
+ """
24
+ When I process "ref.yml"
25
+ Then the output should match JSON
26
+ """
27
+ {
28
+ "AWSTemplateFormatVersion" : "2010-09-09",
29
+ "Attribute" : { "Fn::GetAtt" : [ "BastionHost", "PublicIp" ]}
30
+ }
31
+ """
32
+
33
+ Scenario: Join function call
34
+ Given I have a file "join.yml" containing
35
+ """
36
+ Join: !Join
37
+ - ""
38
+ - [ "string a", "string b" ]
39
+ """
40
+ When I process "join.yml"
41
+ Then the output should match JSON
42
+ """
43
+ {
44
+ "AWSTemplateFormatVersion" : "2010-09-09",
45
+ "Join" : { "Fn::Join" : [ "", [ "string a", "string b" ] ]}
46
+ }
47
+ """
48
+
49
+ Scenario: Join function call with empty strings
50
+ Given I have a file "join.yml" containing
51
+ """
52
+ Join: !Concat [ "string a", "string b" ]
53
+ """
54
+ When I process "join.yml"
55
+ Then the output should match JSON
56
+ """
57
+ {
58
+ "AWSTemplateFormatVersion" : "2010-09-09",
59
+ "Join" : { "Fn::Join" : ["", [ "string a", "string b" ]]}
60
+ }
61
+ """
62
+
63
+ Scenario: FindInMap lookup
64
+ Given I have a file "map.yml" containing
65
+ """
66
+ MapLookup: !FindInMap [Map, Key, Value]
67
+ """
68
+ When I process "map.yml"
69
+ Then the output should match JSON
70
+ """
71
+ {
72
+ "AWSTemplateFormatVersion" : "2010-09-09",
73
+ "MapLookup" : { "Fn::FindInMap" : ["Map", "Key", "Value"] }
74
+ }
75
+ """
76
+
77
+ Scenario: AZ listing
78
+ Given I have a file "map.yml" containing
79
+ """
80
+ AvailabilityZones: !GetAZs us-east-1
81
+ """
82
+ When I process "map.yml"
83
+ Then the output should match JSON
84
+ """
85
+ {
86
+ "AWSTemplateFormatVersion" : "2010-09-09",
87
+ "AvailabilityZones" : { "Fn::GetAZs" : "us-east-1" }
88
+ }
89
+ """
90
+
91
+ Scenario: Base64 string
92
+ Given I have a file "multistring.yml" containing
93
+ """
94
+ mystring: !Base64 |
95
+ Some string
96
+ across multiple
97
+ lines
98
+ """
99
+ When I process "multistring.yml"
100
+ Then the output should match JSON
101
+ """
102
+ {
103
+ "AWSTemplateFormatVersion" : "2010-09-09",
104
+ "mystring" : { "Fn::Base64" : "Some string\nacross multiple\nlines\n" }
105
+ }
106
+ """
107
+
108
+ Scenario: Base64 string with embedded EL
109
+ Given I have a file "embeddedel.yml" containing
110
+ """
111
+ mystring: !Base64 |
112
+ Some string
113
+ across $(Number)
114
+ lines
115
+ """
116
+ When I process "embeddedel.yml"
117
+ Then the output should match JSON
118
+ """
119
+ {
120
+ "AWSTemplateFormatVersion" : "2010-09-09",
121
+ "mystring" :
122
+ { "Fn::Base64" :
123
+ { "Fn::Join": [ "", [
124
+ "Some string\nacross ",
125
+ { "Ref" : "Number" },
126
+ "\nlines\n"
127
+ ]
128
+ ]
129
+ }
130
+ }
131
+ }
132
+ """
@@ -0,0 +1,11 @@
1
+ require "cfoo/cfoo"
2
+ require "cfoo/el_parser"
3
+ require "cfoo/file_system"
4
+ require "cfoo/module"
5
+ require "cfoo/parser"
6
+ require "cfoo/processor"
7
+ require "cfoo/project"
8
+ require "cfoo/renderer"
9
+ require "cfoo/version"
10
+ require "cfoo/yaml"
11
+