chemtrail 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e54ce07e90240967020fa7a8dc856b944338f78e
4
- data.tar.gz: 132975f191f9df48d66606e27648852cb29a8608
3
+ metadata.gz: 0b457fc52081b5875c31d1d124429aa6d438b31a
4
+ data.tar.gz: 77706788871003cba5307760765b907f986a80e4
5
5
  SHA512:
6
- metadata.gz: 0cd2a647db49fb8ecef0863955670ea9dadbec2087e68a561376fbd2c4ca5ea3e55eb883fa404a8d17e2f1b180c5dfbc12d49e42b6d1f5d87e88bdf37f541c25
7
- data.tar.gz: 22f400b9b20b389bec87ba1951f374cb37cd16a5c72359c8debe4913db6d7528cd3106477fb9ea659873cee5d270d06bd9a18d757a6e6155f2dbf57a73a078d0
6
+ metadata.gz: cf6193b91a72aeafb284aa0c928c599a04796379af5d90005fa67caed9b5283f442eb076bf0dd22acbb4f773bb151f505975ac82e095ab7a9f39a3d9bfc8ff7b
7
+ data.tar.gz: d81f93f39b399601bfd3cb96f1bef9314df9e4360f327651a36b9baae7f4635ec11a6c5542fd68d890d88cd894823fad0e7d8d0ad9172d47c7dcb477c14e2a11
data/README.md CHANGED
@@ -33,6 +33,20 @@ Or install it yourself as:
33
33
  Usage
34
34
  -----
35
35
 
36
+ See the `examples/` directory for examples of subclassing and testing templates.
37
+
38
+ Listing all available templates in `lib/templates`:
39
+
40
+ $ chemtrail list
41
+
42
+ Listing templates in a different path:
43
+
44
+ $ chemtrail list --path lib/taco/panic
45
+
46
+ Building a template:
47
+
48
+ $ chemtrail build crazy:cat:pants
49
+
36
50
 
37
51
  Contributing
38
52
  ------------
data/bin/chemtrail CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  lib = File.expand_path("../../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "chemtrail"
5
4
  require "chemtrail/cli"
6
5
  Chemtrail::Cli.start
data/examples/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ guard :rspec do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch('spec/spec_helper.rb') { "spec" }
7
+ end
8
+
@@ -0,0 +1,53 @@
1
+ AWSNATAMI:
2
+ us-east-1:
3
+ AMI: ami-c6699baf
4
+ us-west-2:
5
+ AMI: ami-52ff7262
6
+ us-west-1:
7
+ AMI: ami-3bcc9e7e
8
+ eu-west-1:
9
+ AMI: ami-0b5b6c7f
10
+ ap-southeast-1:
11
+ AMI: ami-02eb9350
12
+ ap-southeast-2:
13
+ AMI: ami-ab990e91
14
+ ap-northeast-1:
15
+ AMI: ami-14d86d15
16
+ sa-east-1:
17
+ AMI: ami-0439e619
18
+
19
+ AWSInstanceType2Arch:
20
+ t1.micro:
21
+ Arch: "64"
22
+ m1.small:
23
+ Arch: "64"
24
+ m1.medium:
25
+ Arch: "64"
26
+ m1.large:
27
+ Arch: "64"
28
+ m1.xlarge:
29
+ Arch: "64"
30
+ m2.xlarge:
31
+ Arch: "64"
32
+ m2.2xlarge:
33
+ Arch: "64"
34
+ m2.4xlarge:
35
+ Arch: "64"
36
+ c1.medium:
37
+ Arch: "64"
38
+ c1.xlarge:
39
+ Arch: "64"
40
+ cc1.4xlarge:
41
+ Arch: 64Cluster
42
+ cc2.8xlarge:
43
+ Arch: 64Cluster
44
+ cg1.4xlarge:
45
+ Arch: 64GPU
46
+
47
+ SubnetConfig:
48
+ VPC:
49
+ CIDR: 10.0.0.0/16
50
+ Public:
51
+ CIDR: 10.0.0.0/24
52
+ Private:
53
+ CIDR: 10.0.1.0/24
@@ -0,0 +1,18 @@
1
+ NATInstanceType:
2
+ Default: m1.small
3
+ Description: NAT Device EC2 instance type
4
+ ConstraintDescription: must be a valid EC2 instance type.
5
+ AllowedValues:
6
+ - t1.micro
7
+ - m1.small
8
+ - m1.medium
9
+ - m1.large
10
+ - m1.xlarge
11
+ - m2.xlarge
12
+ - m2.2xlarge
13
+ - m2.4xlarge
14
+ - c1.medium
15
+ - c1.xlarge
16
+ - cc1.4xlarge
17
+ - cc2.8xlarge
18
+ - cg1.4xlarge
@@ -0,0 +1,44 @@
1
+ require "chemtrail"
2
+ require "yaml"
3
+
4
+ class OpsworksVpc < Chemtrail::Template
5
+ def description
6
+ <<-DESCRIPTION.strip.gsub!(/\s+/, ' ')
7
+ Sample template showing how to create a VPC environment for AWS OpsWorks.
8
+ The stack contains 2 subnets: the first subnet is public and contains the
9
+ load balancer, a NAT device for internet access from the private subnet.
10
+ The second subnet is private.
11
+
12
+ You will be billed for the AWS resources used if you create a stack from
13
+ this template.
14
+ DESCRIPTION
15
+ end
16
+
17
+ def parameters
18
+ [
19
+ Chemtrail::Parameter.new("NATInstanceType", "String", parameters_config["NATInstanceType"])
20
+ ]
21
+ end
22
+
23
+ def mappings
24
+ [
25
+ Chemtrail::Mapping.new("AWSNATAMI", mappings_config["AWSNATAMI"]),
26
+ Chemtrail::Mapping.new("AWSInstanceType2Arch", mappings_config["AWSInstanceType2Arch"]),
27
+ Chemtrail::Mapping.new("SubnetConfig", mappings_config["SubnetConfig"])
28
+ ]
29
+ end
30
+
31
+ protected
32
+
33
+ def parameters_config
34
+ @parameters_config ||= YAML.load_file(File.expand_path("../config/parameters.yml", __FILE__))
35
+ end
36
+
37
+ def mappings_config
38
+ @mappings_config ||= YAML.load_file(File.expand_path("../config/mappings.yml", __FILE__))
39
+ end
40
+
41
+ def resources_config
42
+ @resources_config ||= YAML.load_file(File.expand_path("../config/resources.yml", __FILE__))
43
+ end
44
+ end
@@ -0,0 +1,30 @@
1
+ require "spec_helper"
2
+
3
+ describe OpsworksVpc do
4
+ subject(:template) { OpsworksVpc.new }
5
+
6
+ its(:description) { should include("VPC environment for AWS OpsWorks") }
7
+
8
+ describe "#parameters" do
9
+ it { should have_parameter("NATInstanceType").with_type("String") }
10
+
11
+ it { should have_field("Default").with_value("m1.small").on("NATInstanceType") }
12
+ it { should have_field("AllowedValues").including("t1.micro").on("NATInstanceType") }
13
+ it { should have_field("ConstraintDescription").including("valid EC2 instance").on("NATInstanceType") }
14
+ end
15
+
16
+ describe "#mappings" do
17
+ it { should have_mapping("AWSNATAMI") }
18
+ it { should have_mapping("AWSInstanceType2Arch") }
19
+ it { should have_mapping("SubnetConfig") }
20
+
21
+ it { should have_mapping_key("us-east-1").including("AMI" => "ami-c6699baf").on("AWSNATAMI") }
22
+ it { should have_mapping_key("m1.medium").including("Arch" => "64").on("AWSInstanceType2Arch") }
23
+ it { should have_mapping_key("VPC").including("CIDR" => "10.0.0.0/16").on("SubnetConfig") }
24
+ it { should have_mapping_key("Public").including("CIDR" => "10.0.0.0/24").on("SubnetConfig") }
25
+ it { should have_mapping_key("Private").including("CIDR" => "10.0.1.0/24").on("SubnetConfig") }
26
+ end
27
+
28
+ describe "#resources" do
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ $:<< File.expand_path("../../../lib", __FILE__)
2
+
3
+ require "chemtrail"
4
+ require "chemtrail/rspec"
5
+
6
+ Dir.glob(File.expand_path("../../lib/templates/**/*_template.rb", __FILE__)).each { |t| require t }
7
+
8
+ RSpec.configure do |config|
9
+ config.include Chemtrail::RSpec
10
+ config.treat_symbols_as_metadata_keys_with_true_values = true
11
+ config.run_all_when_everything_filtered = true
12
+ config.filter_run :focus
13
+ config.order = 'random'
14
+ end
15
+
data/lib/chemtrail/cli.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "thor"
2
2
  require "json"
3
+ require "chemtrail"
3
4
 
4
5
  class Chemtrail::Cli < Thor
5
6
  default_task :list
@@ -3,8 +3,9 @@ require "chemtrail/reference_presenter"
3
3
  class Chemtrail::Mapping
4
4
  attr_reader :id
5
5
 
6
- def initialize(id)
6
+ def initialize(id, entries = nil)
7
7
  @id = id
8
+ @entries = entries
8
9
  end
9
10
 
10
11
  def entries
@@ -1,14 +1,14 @@
1
1
  class Chemtrail::Parameter
2
2
  attr_reader :id, :type
3
3
 
4
- def initialize(id, type, specifications = {})
4
+ def initialize(id, type, fields = {})
5
5
  @id = id
6
6
  @type = type
7
- @specifications = specifications
7
+ @fields = fields
8
8
  end
9
9
 
10
- def specifications
11
- @specifications ||= {}
10
+ def fields
11
+ @fields ||= {}
12
12
  end
13
13
 
14
14
  def to_reference
@@ -21,7 +21,7 @@ class Chemtrail::Parameter
21
21
  {
22
22
  id => {
23
23
  "Type" => type
24
- }.merge(specifications)
24
+ }.merge(fields)
25
25
  }
26
26
  end
27
27
  end
@@ -0,0 +1,131 @@
1
+ require "chemtrail"
2
+ require "rspec/expectations"
3
+
4
+ module Chemtrail::RSpec
5
+ extend RSpec::Matchers::DSL
6
+
7
+ matcher :have_parameter do |parameter_id|
8
+ define_method :parameter_for do |actual|
9
+ actual.parameters.detect { |param| param.id == parameter_id }
10
+ end
11
+
12
+ define_method :matches_type? do |actual|
13
+ @type.nil? || parameter_for(actual).type == @type
14
+ end
15
+
16
+ match do |actual|
17
+ !parameter_for(actual).nil? && matches_type?(actual)
18
+ end
19
+
20
+ chain :with_type do |type|
21
+ @type = type
22
+ end
23
+
24
+ failure_message_for_should do |actual|
25
+ if parameter = parameter_for(actual)
26
+ %(expected parameter #{parameter_id.inspect} to have type #{@type.inspect}, but got #{parameter.type.inspect})
27
+ else
28
+ %(expected to find parameter #{parameter_id.inspect}, but got nothing)
29
+ end
30
+ end
31
+ end
32
+
33
+ matcher :have_field do |field_name|
34
+ define_method :parameter_for do |actual|
35
+ actual.parameters.detect { |p| p.id == @parameter_id }
36
+ end
37
+
38
+ define_method :field_for do |parameter|
39
+ parameter.fields[field_name]
40
+ end
41
+
42
+ define_method :matches_value? do |field|
43
+ if @value
44
+ field == @value
45
+ elsif @included_value
46
+ field.include?(@included_value)
47
+ else
48
+ true
49
+ end
50
+ end
51
+
52
+ match do |actual|
53
+ parameter = parameter_for(actual)
54
+ field = field_for(parameter)
55
+ !parameter.nil? && !field.nil? && matches_value?(field)
56
+ end
57
+
58
+ chain :on do |parameter_id|
59
+ @parameter_id = parameter_id
60
+ end
61
+
62
+ chain :with_value do |value|
63
+ @value = value
64
+ end
65
+
66
+ chain :including do |value|
67
+ @included_value = value
68
+ end
69
+
70
+ failure_message_for_should do |actual|
71
+ if parameter = parameter_for(actual)
72
+ if field = field_for(parameter)
73
+ expected_field = @value || @included_value
74
+ %(expected parameter #{@parameter_id.inspect} field #{field_name.inspect} to have value #{expected_field.inspect}, but got #{field.inspect})
75
+ else
76
+ %(expected parameter #{@parameter_id.inspect} to have type #{field_name.inspect})
77
+ end
78
+ else
79
+ %(expected to find parameter #{@parameter_id.inspect}, but got nothing)
80
+ end
81
+ end
82
+ end
83
+
84
+ matcher :have_mapping do |expected|
85
+ match { |actual| actual.mappings.any? { |m| m.id == expected } }
86
+ end
87
+
88
+ matcher :have_mapping_key do |entry_name|
89
+ define_method :mapping_for do |actual|
90
+ actual.mappings.detect { |m| m.id == @mapping_id }
91
+ end
92
+
93
+ define_method :entry_for do |mapping|
94
+ mapping.entries[entry_name]
95
+ end
96
+
97
+ define_method :matches_value? do |entry|
98
+ if @included_value
99
+ entry.values_at(*@included_value.keys) == @included_value.values
100
+ else
101
+ true
102
+ end
103
+ end
104
+
105
+ match do |actual|
106
+ mapping = mapping_for(actual)
107
+ entry = entry_for(mapping)
108
+ !mapping.nil? && !entry.nil? && matches_value?(entry)
109
+ end
110
+
111
+ chain :on do |mapping_id|
112
+ @mapping_id = mapping_id
113
+ end
114
+
115
+ chain :including do |value|
116
+ @included_value = value
117
+ end
118
+
119
+ failure_message_for_should do |actual|
120
+ if mapping = mapping_for(actual)
121
+ if entry = entry_for(mapping)
122
+ %(expected mapping #{@mapping_id.inspect} field #{entry_name.inspect} to have value #{@included_value.inspect}, but got #{entry.inspect})
123
+ else
124
+ %(expected mapping #{@mapping_id.inspect} to have type #{entry_name.inspect})
125
+ end
126
+ else
127
+ %(expected to find mapping #{@mapping_id.inspect}, but got nothing)
128
+ end
129
+ end
130
+ end
131
+ end
@@ -1,3 +1,3 @@
1
1
  module Chemtrail
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -5,8 +5,9 @@ describe Chemtrail::Cli do
5
5
 
6
6
  describe "#list" do
7
7
  it "lists available templates" do
8
- Kernel.should_receive(:puts).with("tacos")
9
- cli.list
8
+ got_tacos = false
9
+ Kernel.stub(:puts) { |string| got_tacos ||= (string == "tacos") }
10
+ expect { cli.list }.to change{ got_tacos }.to(true)
10
11
  end
11
12
  end
12
13
 
@@ -5,13 +5,19 @@ describe Chemtrail::Mapping do
5
5
 
6
6
  describe "#to_hash" do
7
7
  context "when there are no entries" do
8
- its(:to_hash) { should have_key "atlas" }
8
+ its(:to_hash) { should == {"atlas" => {}} }
9
9
  end
10
10
 
11
11
  context "when an entry has been added" do
12
- before { mapping.entries["teeth"] = {} }
12
+ before { mapping.entries[:teeth] = {} }
13
13
 
14
- specify { mapping.to_hash["atlas"].should have_key "teeth" }
14
+ specify { mapping.to_hash["atlas"].should == {teeth: {}} }
15
+ end
16
+
17
+ context "when an entry is passed into the initializer" do
18
+ subject(:mapping) { Chemtrail::Mapping.new("atlas", charles: {}) }
19
+
20
+ specify { mapping.to_hash["atlas"].should == {charles: {}} }
15
21
  end
16
22
  end
17
23
 
@@ -3,15 +3,15 @@ require "spec_helper"
3
3
  describe Chemtrail::Parameter do
4
4
  subject(:parameter) { Chemtrail::Parameter.new("parmesan", "String") }
5
5
 
6
- describe "#specifications" do
7
- context "when there are no specifications" do
8
- its(:specifications) { should be_empty }
6
+ describe "#fields" do
7
+ context "when there are no fields" do
8
+ its(:fields) { should be_empty }
9
9
  end
10
10
 
11
11
  context "when a specification has been passed into the initializer" do
12
12
  subject(:parameter) { Chemtrail::Parameter.new("parmesan", "String", ok: "great") }
13
13
 
14
- its(:specifications) { should == {ok: "great"} }
14
+ its(:fields) { should == {ok: "great"} }
15
15
  end
16
16
  end
17
17
 
@@ -24,7 +24,7 @@ describe Chemtrail::Parameter do
24
24
  specify { parameter.to_hash["parmesan"].should include("Type" => "String") }
25
25
 
26
26
  context "when there is a specification" do
27
- before { parameter.specifications[:ducks] = "amazing" }
27
+ before { parameter.fields[:ducks] = "amazing" }
28
28
 
29
29
  specify { parameter.to_hash["parmesan"].should include(ducks: "amazing") }
30
30
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chemtrail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Doc Ritezel
@@ -99,6 +99,13 @@ files:
99
99
  - README.md
100
100
  - bin/chemtrail
101
101
  - chemtrail.gemspec
102
+ - examples/.rspec
103
+ - examples/Guardfile
104
+ - examples/lib/templates/config/mappings.yml
105
+ - examples/lib/templates/config/parameters.yml
106
+ - examples/lib/templates/opsworks_vpc_template.rb
107
+ - examples/spec/lib/templates/opsworks_vpc_template_spec.rb
108
+ - examples/spec/spec_helper.rb
102
109
  - lib/chemtrail.rb
103
110
  - lib/chemtrail/class_name_inflector.rb
104
111
  - lib/chemtrail/cli.rb
@@ -109,6 +116,7 @@ files:
109
116
  - lib/chemtrail/property_list.rb
110
117
  - lib/chemtrail/reference_presenter.rb
111
118
  - lib/chemtrail/resource.rb
119
+ - lib/chemtrail/rspec.rb
112
120
  - lib/chemtrail/section_presenter.rb
113
121
  - lib/chemtrail/template.rb
114
122
  - lib/chemtrail/version.rb