cfoo 0.0.1

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