awsdsl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/awsdsl/dsl.rb ADDED
@@ -0,0 +1,79 @@
1
+ require 'awsdsl/ext/proc'
2
+ require 'awsdsl/ext/symbol'
3
+ require 'active_support/core_ext/object/blank'
4
+ require 'awsdsl/fn'
5
+
6
+ module AWSDSL
7
+ module DSL
8
+ include Fn
9
+ attr_accessor :name
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+
15
+ def initialize(name, &block)
16
+ @name = name
17
+ self.class.class_eval do
18
+ attributes.each do |attr|
19
+ define_method(attr) do |*args|
20
+ if args.length > 0
21
+ args = args.length > 1 ? args : args.first
22
+ instance_variable_set(attr.ivar, args)
23
+ else
24
+ instance_variable_get(attr.ivar)
25
+ end
26
+ end
27
+ end
28
+
29
+ multi_attributes.each do |attr|
30
+ define_method(attr) do |*args|
31
+ cur = instance_variable_get(attr.plural_ivar) || []
32
+ instance_variable_set(attr.plural_ivar, cur + args)
33
+ end
34
+ define_method(attr.plural_fn) do |*_, &_|
35
+ instance_variable_get(attr.plural_ivar) || []
36
+ end
37
+ end
38
+
39
+ sub_components.each do |attr|
40
+ define_method(attr) do |*args, &b|
41
+ cur = instance_variable_get(attr.plural_ivar) || []
42
+ klass_name = attr.to_s.split('_').collect!(&:capitalize).join
43
+ klass = Object.const_get("AWSDSL::#{klass_name}")
44
+ instance_variable_set(attr.plural_ivar, cur + [klass.new(args.first, &b)])
45
+ end
46
+ define_method(attr.plural_fn) do |*_, &_|
47
+ instance_variable_get(attr.plural_ivar) || []
48
+ end
49
+ end
50
+ end
51
+
52
+ instance_eval(&block) if block_given?
53
+ end
54
+
55
+ def to_h
56
+ h = {}
57
+ (self.class.attributes + [:name]).each { |attr| h.store(attr, send(attr)) }
58
+ self.class.multi_attributes.each { |attr| h.store(attr.plural_fn, send(attr.plural_fn)) }
59
+ self.class.sub_components.each do |attr|
60
+ comp = send(attr.plural_fn).map(&:to_h)
61
+ h.store(attr.plural_fn, comp)
62
+ end
63
+ h.delete_if { |_, v| v.blank? }
64
+ h
65
+ end
66
+
67
+ module ClassMethods
68
+ [:sub_components, :attributes, :multi_attributes].each do |method|
69
+ define_method(method) do |*args|
70
+ if args.length > 0
71
+ instance_variable_set(method.ivar, args)
72
+ else
73
+ instance_variable_get(method.ivar) || []
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,14 @@
1
+ require 'active_support/core_ext/kernel/singleton_class'
2
+
3
+ class Proc
4
+ def bind(object)
5
+ block, time = self, Time.now
6
+ object.class_eval do
7
+ method_name = "__bind_#{time.to_i}_#{time.usec}"
8
+ define_method(method_name, &block)
9
+ method = instance_method(method_name)
10
+ remove_method(method_name)
11
+ method
12
+ end.bind(object)
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ class Symbol
2
+ def ivar
3
+ "@#{self}".to_sym
4
+ end
5
+
6
+ def plural_ivar
7
+ "@#{self}s".to_sym
8
+ end
9
+
10
+ def plural_fn
11
+ "#{self}s".to_sym
12
+ end
13
+ end
data/lib/awsdsl/fn.rb ADDED
@@ -0,0 +1,7 @@
1
+ module AWSDSL
2
+ module Fn
3
+ def stack(*a, &block)
4
+ Stack.new(*a, &block)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,24 @@
1
+ require 'awsdsl/dsl'
2
+ require 'awsdsl/dsl/stack'
3
+ require 'awsdsl/dsl/role'
4
+ require 'awsdsl/dsl/role_profile'
5
+ require 'awsdsl/dsl/load_balancer'
6
+ require 'awsdsl/dsl/elasticache'
7
+ require 'awsdsl/dsl/vpc'
8
+ require 'awsdsl/dsl/subnet'
9
+ require 'awsdsl/fn'
10
+
11
+ module AWSDSL
12
+ module Loader
13
+ def self.stack(*a, &block)
14
+ Stack.new(*a, &block)
15
+ end
16
+
17
+ def self.load(fname)
18
+ stack = binding.eval(File.read(fname), fname)
19
+ # TODO(jpg): Add default profiles to stack
20
+ stack.mixin_profiles
21
+ stack
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ module AWSDSL
2
+ class Runner
3
+ def initialize(stackfile: 'Stackfile')
4
+ @stack = Loader.load(stackfile)
5
+ @cfn = AWS::CloudFormation.new
6
+ end
7
+
8
+ def build_amis
9
+ AMIBuilder.build(@stack)
10
+ end
11
+
12
+ def create
13
+ build_amis
14
+ t = CfnBuilder.build(@stack)
15
+ @cfn.stacks.create(@stack.name, t, capabilities: ['CAPABILITY_IAM'])
16
+ end
17
+
18
+ def update
19
+ build_amis
20
+ t = CfnBuilder.build(stack)
21
+ @cfn.stacks[@stack.name].update(template: t, capabiltiies: ['CAPABILITY_IAM'])
22
+ end
23
+
24
+ def delete
25
+ @cfn.stacks[@stack.name].delete
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module AWSDSL
2
+ VERSION = '0.0.1'
3
+ end
data/lib/awsdsl.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'awsdsl/loader'
2
+ require 'awsdsl/cfn_builder'
3
+ require 'awsdsl/ami_builder'
4
+
5
+ module AWSDSL
6
+ end
@@ -0,0 +1,28 @@
1
+ require 'English'
2
+ require 'awsdsl'
3
+ require 'pry'
4
+
5
+ module AWSDSL
6
+ describe CfnBuilder do
7
+ describe :build do
8
+ it 'should build the test stack' do
9
+ stack = Loader.load(fixture_path('test_stack.rb'))
10
+ CfnBuilder.new(stack).build
11
+ end
12
+
13
+ it 'should generate valid cloudformation', type: :integration do
14
+ stack = Loader.load(fixture_path('test_stack.rb'))
15
+ stack.roles.each do |role|
16
+ role.ami = 'ami-id'
17
+ end
18
+ json = CfnBuilder.new(stack).build.to_json
19
+ temp = Tempfile.new('awsdsl_cfn_json')
20
+ temp.write(json)
21
+ `aws cloudformation validate-template --template-body file://#{temp.path}`
22
+ temp.close
23
+ temp.unlink
24
+ expect($CHILD_STATUS.exitstatus).to eq(0)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,12 @@
1
+ require 'awsdsl'
2
+ require 'pry'
3
+
4
+ module AWSDSL
5
+ describe Loader do
6
+ describe :load do
7
+ it 'should load the test data' do
8
+ Loader.load(fixture_path('test_stack.rb'))
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,100 @@
1
+ stack 'logs' do
2
+ description 'logstash cluster'
3
+ ssl_cert_arn = 'arn:aws:iam::account_id::certificate'
4
+ zone_arn = 'arn:aws:route53:::hostedzone/zone_id'
5
+ snapshot_bucket_arn = 'arn:aws:s3:::snapshot_bucket'
6
+ cloudtrail_queue_arn = 'arn:aws:sqs:ap-southeast-2:account_id:queue'
7
+
8
+ vpc 'logs' do
9
+ region 'ap-southeast-2'
10
+ subnet 'public' do
11
+ az 'a', 'b'
12
+ end
13
+ subnet 'private' do
14
+ az 'a', 'b'
15
+ igw false
16
+ end
17
+ end
18
+
19
+ role_profile 'es_comms' do
20
+ security_group 'sg-id'
21
+ subnet 'public'
22
+ vpc 'logs'
23
+ end
24
+
25
+ role_profile 'es_bucket' do
26
+ policy_statement effect: 'Allow', action: 's3:ListBucket', resource: snapshot_bucket_arn
27
+ policy_statement effect: 'Allow',
28
+ action: %w(s3:GetObject s3:PutObjecs3:DeleteObject s3:DeleteObject),
29
+ resource: "#{snapshot_bucket_arn}/*"
30
+ end
31
+
32
+ role_profile 'ec2_discovery' do
33
+ policy_statement effect: 'Allow', action: 'ec2:DescribeInstances', resource: '*'
34
+ end
35
+
36
+ role 'logstash' do
37
+ include_profile 'ec2_discovery', 'es_comms'
38
+ load_balancer 'logstash' do
39
+ listener port: 80
40
+ listener port: 443, proto: 'HTTPS', cert: ssl_cert_arn
41
+ listener port: 9000, proto: 'TCP'
42
+ dns_record name: 'logstash.zone.com', zone: 'zone-id'
43
+ health_check target: 'HTTP:80/health'
44
+ end
45
+ policy_statement effect: 'Allow', action: 'sqs:*', resource: cloudtrail_queue_arn
46
+ min_size 2
47
+ max_size 4
48
+ tgt_size 2
49
+ update_policy pause_time: '5M'
50
+ instance_type 't2.micro'
51
+ chef_provisioner runlist: 'logstash'
52
+ end
53
+
54
+ role 'elasticsearch' do
55
+ include_profile 'ec2_discovery', 'es_bucket', 'es_comms'
56
+ load_balancer 'elasticsearch' do
57
+ listener port: 9200
58
+ health_check target: 'HTTP:9200/'
59
+ dns_record name: 'elasticsearch.zone.com', zone: 'zone-id'
60
+ security_group 'sg-id'
61
+ internal true
62
+ end
63
+ min_size 3
64
+ max_size 5
65
+ tgt_size 5
66
+ update_policy pause_time: '10M', min_inservice: 3
67
+ instance_type 't2.micro'
68
+ block_device name: '/dev/sda1', size: 20
69
+ chef_provisioner runlist: 'elasticsearch'
70
+ allow role: 'logstash', ports: 9200
71
+ allow role: 'utility', ports: 9200
72
+ allow role: 'elasticsearch', ports: 9200
73
+ end
74
+
75
+ role 'utility' do
76
+ include_profile 'es_bucket', 'es_comms'
77
+ policy_statement effect: 'Allow',
78
+ action: [
79
+ 'route53:ChangeResourceRecordSets',
80
+ 'route53:GetHostedZone',
81
+ 'route53:ListResourceRecordSets'
82
+ ],
83
+ resource: zone_arn
84
+ policy_statement effect: 'Allow', action: 'route53:ListHostedZones', resource: '*'
85
+ min_size 0
86
+ max_size 1
87
+ tgt_size 1
88
+ update_policy min_inservice: 0
89
+ instance_type 't2.micro'
90
+ chef_provisioner runlist: 'utility'
91
+ end
92
+
93
+ elasticache 'redis' do
94
+ vpc 'logs'
95
+ subnet 'private'
96
+ engine 'redis'
97
+ node_type 't2.micro'
98
+ allow role: 'logstash'
99
+ end
100
+ end
@@ -0,0 +1,30 @@
1
+ require 'pry'
2
+ require 'awsdsl'
3
+ require 'awsdsl/cfn_helpers'
4
+
5
+ ROOT = File.join(File.dirname(__FILE__), '..')
6
+ FIXTURES = File.join(File.dirname(__FILE__), 'fixtures')
7
+
8
+ def fixture_path(*path)
9
+ File.join(FIXTURES, path)
10
+ end
11
+
12
+ def fixture(*path)
13
+ File.open(fixture_path(path)) { |f| f.read }
14
+ end
15
+
16
+ def json_fixture(*path)
17
+ last = path.pop
18
+ JSON.parse(fixture(path << last + '.json'))
19
+ end
20
+
21
+ def yaml_fixture(*path)
22
+ last = path.pop
23
+ YAML.parse(fixture(path << last + '.yml'))
24
+ end
25
+
26
+ AWS.stub!
27
+
28
+ RSpec.configure do |config|
29
+ config.filter_run_excluding type: 'integration' unless ENV['INTEGRATION']
30
+ end
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: awsdsl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Joseph Glanville
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: clamp
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: cfndsl
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: gersberms
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: netaddr
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.5'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.5'
97
+ description: A simple DSL for deploying and running apps on AWS
98
+ email:
99
+ - jpg@jpg.id.au
100
+ executables:
101
+ - awsdsl
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - Gemfile
108
+ - Gemfile.lock
109
+ - README.md
110
+ - Rakefile
111
+ - awsdsl.gemspec
112
+ - bin/awsdsl
113
+ - lib/awsdsl.rb
114
+ - lib/awsdsl/ami_builder.rb
115
+ - lib/awsdsl/base_ami.rb
116
+ - lib/awsdsl/cfn_builder.rb
117
+ - lib/awsdsl/cfn_helpers.rb
118
+ - lib/awsdsl/command_line.rb
119
+ - lib/awsdsl/dsl.rb
120
+ - lib/awsdsl/dsl/elasticache.rb
121
+ - lib/awsdsl/dsl/load_balancer.rb
122
+ - lib/awsdsl/dsl/role.rb
123
+ - lib/awsdsl/dsl/role_profile.rb
124
+ - lib/awsdsl/dsl/stack.rb
125
+ - lib/awsdsl/dsl/subnet.rb
126
+ - lib/awsdsl/dsl/vpc.rb
127
+ - lib/awsdsl/ext/proc.rb
128
+ - lib/awsdsl/ext/symbol.rb
129
+ - lib/awsdsl/fn.rb
130
+ - lib/awsdsl/loader.rb
131
+ - lib/awsdsl/runner.rb
132
+ - lib/awsdsl/version.rb
133
+ - spec/awsdsl/cfn_builder_spec.rb
134
+ - spec/awsdsl/loader_spec.rb
135
+ - spec/fixtures/test_stack.rb
136
+ - spec/spec_helper.rb
137
+ homepage: https://github.com/josephglanville/awsdsl
138
+ licenses:
139
+ - MIT
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 2.4.3
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: A simple DSL for deploying and running apps on AWS
161
+ test_files:
162
+ - spec/awsdsl/cfn_builder_spec.rb
163
+ - spec/awsdsl/loader_spec.rb
164
+ - spec/fixtures/test_stack.rb
165
+ - spec/spec_helper.rb