dslh 0.1.8 → 0.1.9

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: 22c5f3ef5ed8d62be6f01f66185d03c69746a21f
4
- data.tar.gz: 07f1988d59dd1f91dde43e9dcc7b9412122dc3b0
3
+ metadata.gz: 041bb7cf886d6a16fb6be02ba6ef356bf31810c7
4
+ data.tar.gz: b96cb8ee97322d53745dda628eca4e8fe6ace944
5
5
  SHA512:
6
- metadata.gz: 7c6d12ec8eed101cd59bf56c8bf452086c224196428f38275769bc89ef688c3db64f120d907b3d9737542e379c4ec33bac13dd512a9b5c3e301aab0d38637090
7
- data.tar.gz: 4278f2189e6ca73c321b5d341835b4e6e0b645f337ca288ad016481bf90f241f27fe2129fb207866c08c61b5f4b9d85490bc3ec739258373c8d1b90415b2ca68
6
+ metadata.gz: 6753cfa8efa4438bcdfb2193bb827c4268c65bef24f302d2494c759047de84442d3b318dc79871e013214641aca7e19e99e0c102e9256c53eb47fd8dab069d0a
7
+ data.tar.gz: 7d43a7ca6c3633460e47e5251dbadcb7336f7f6e342965bda4404737c2426fc9fe17125d718b221de5b33860bd6c36c706670282da265e5dfd46c0fcb93b8e8c
data/lib/dslh.rb CHANGED
@@ -76,6 +76,7 @@ class Dslh
76
76
  next_indent = (INDENT_SPACES * (depth + 1))
77
77
  key_conv = @options[:key_conv] || @options[:conv]
78
78
  value_conv = @options[:value_conv] || @options[:conv]
79
+ nested = false
79
80
 
80
81
  if exclude_key?(key_conv, hash.keys)
81
82
  buf.puts('(' + ("\n" + hash.pretty_inspect.strip).gsub("\n", "\n" + indent) + ')')
@@ -83,86 +84,96 @@ class Dslh
83
84
  end
84
85
 
85
86
  hash.each do |key, value|
86
- key = key_conv.call(key) if key_conv
87
- buf.print(indent + key)
87
+ value_proc = proc do |value_buf|
88
+ case value
89
+ when Hash
90
+ if exclude_key?(key_conv, value.keys)
91
+ value_buf.puts('(' + ("\n" + value.pretty_inspect.strip).gsub("\n", "\n" + next_indent) + ')')
92
+ else
93
+ nested = true
94
+ value_buf.puts(' do')
95
+ deval0(value, depth + 1, value_buf)
96
+ value_buf.puts(indent + 'end')
97
+ end
98
+ when Array
99
+ if value.any? {|v| [Array, Hash].any? {|c| v.kind_of?(c) }}
100
+ nested = true
101
+ value_buf.puts(' [')
102
+
103
+ value.each_with_index do |v, i|
104
+ if v.kind_of?(Hash)
105
+ value_buf.puts(next_indent + '_{')
106
+ deval0(v, depth + 2, value_buf)
107
+ value_buf.print(next_indent + '}')
108
+ else
109
+ value_buf.print(next_indent + v.pretty_inspect.strip.gsub("\n", "\n" + next_indent))
110
+ end
111
+
112
+ value_buf.puts(i < (value.length - 1) ? ',' : '')
113
+ end
88
114
 
89
- case value
90
- when Hash
91
- if exclude_key?(key_conv, value.keys)
92
- buf.puts('(' + ("\n" + value.pretty_inspect.strip).gsub("\n", "\n" + next_indent) + ')')
115
+ value_buf.puts(indent + ']')
116
+ elsif value.length == 1
117
+ value_buf.puts(' ' + value.inspect)
118
+ else
119
+ value_buf.puts(' ' + value.map {|v|
120
+ v = value_conv.call(v) if value_conv
121
+
122
+ if v.kind_of?(Hash)
123
+ '(' + v.inspect + ')'
124
+ else
125
+ v.inspect
126
+ end
127
+ }.join(', '))
128
+ end
93
129
  else
94
- buf.puts(' do')
95
- deval0(value, depth + 1, buf)
96
- buf.puts(indent + 'end')
130
+ value = value_conv.call(value) if value_conv
131
+ value_buf.puts(' ' + value.inspect)
97
132
  end
98
- when Array
99
- if value.any? {|v| [Array, Hash].any? {|c| v.kind_of?(c) }}
100
- buf.puts(' [')
101
-
102
- value.each_with_index do |v, i|
103
- if v.kind_of?(Hash)
104
- buf.puts(next_indent + '_{')
105
- deval0(v, depth + 2, buf)
106
- buf.print(next_indent + '}')
107
- else
108
- buf.print(next_indent + v.pretty_inspect.strip.gsub("\n", "\n" + next_indent))
109
- end
133
+ end
110
134
 
111
- buf.puts(i < (value.length - 1) ? ',' : '')
112
- end
135
+ key = key_conv.call(key) if key_conv
113
136
 
114
- buf.puts(indent + ']')
115
- elsif value.length == 1
116
- buf.puts(' ' + value.inspect)
117
- else
118
- buf.puts(' ' + value.map {|v|
119
- v = value_conv.call(v) if value_conv
137
+ if key.kind_of?(Proc)
138
+ tmp_buf = StringIO.new
139
+ value_proc.call(tmp_buf)
120
140
 
121
- if v.kind_of?(Hash)
122
- '(' + v.inspect + ')'
123
- else
124
- v.inspect
125
- end
126
- }.join(', '))
127
- end
141
+ key_value = case key.arity
142
+ when 0
143
+ key.call
144
+ when 1
145
+ key.call(tmp_buf.string.strip)
146
+ else
147
+ key.call(tmp_buf.string.strip, nested)
148
+ end
149
+
150
+ buf.puts(indent + key_value)
128
151
  else
129
- value = value_conv.call(value) if value_conv
130
- buf.puts(' ' + value.inspect)
152
+ buf.print(indent + key)
153
+ value_proc.call(buf)
131
154
  end
132
155
  end
133
156
  end
134
157
 
135
158
  def exclude_key?(key_conv, keys)
136
159
  exclude_key = @options[:exclude_key] || proc {|k| k.to_s !~ /\A[_a-z]\w+\Z/i }
137
- exclude_key and (key_conv ? keys.map {|k| key_conv.call(k) } : keys).any? {|k| exclude_key.call(k) }
160
+
161
+ if not @options.has_key?(:exclude_key) and key_conv
162
+ keys = keys.map {|k| key_conv.call(k) }
163
+ end
164
+
165
+ keys.any? {|k| exclude_key.call(k) }
138
166
  end
139
167
 
140
168
  class Scope
141
169
  def _(&block)
142
- if block
143
- hash_orig = @__hash__
144
- @__hash__ = {}
145
- self.instance_eval(&block)
146
- nested_hash = @__hash__
147
- @__hash__ = hash_orig
148
- return nested_hash
149
- end
170
+ ScopeBlock.nest(binding, 'block')
150
171
  end
151
172
 
152
173
  def method_missing(method_name, *args, &block)
153
174
  key_conv = @__options__[:key_conv] || @__options__[:conv]
154
175
  value_conv = @__options__[:value_conv] || @__options__[:conv]
155
-
156
- nested_hash = nil
157
-
158
- if block
159
- hash_orig = @__hash__
160
- @__hash__ = {}
161
- self.instance_eval(&block)
162
- nested_hash = @__hash__
163
- @__hash__ = hash_orig
164
- end
165
-
176
+ nested_hash = ScopeBlock.nest(binding, 'block')
166
177
  method_name = key_conv.call(method_name) if key_conv
167
178
 
168
179
  if args.empty?
@@ -183,4 +194,21 @@ class Dslh
183
194
  end
184
195
  end
185
196
  end # of Scope
197
+
198
+ class ScopeBlock
199
+ def self.nest(bind, block_var)
200
+ eval(<<-EOS, bind)
201
+ if #{block_var}
202
+ __hash_orig = @__hash__
203
+ @__hash__ = {}
204
+ self.instance_eval(&#{block_var})
205
+ __nested_hash = @__hash__
206
+ @__hash__ = __hash_orig
207
+ __nested_hash
208
+ else
209
+ nil
210
+ end
211
+ EOS
212
+ end
213
+ end
186
214
  end
data/lib/dslh/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Dslh
2
- VERSION = '0.1.8'
2
+ VERSION = '0.1.9'
3
3
  end
@@ -0,0 +1,455 @@
1
+ {
2
+ "AWSTemplateFormatVersion" : "2010-09-09",
3
+
4
+ "Description" : "AWS CloudFormation Sample Template Drupal_Multi_AZ. Drupal is an open source content management platform powering millions of websites and applications. This template installs a highly-available, scalable Drupal deployment using a multi-az Amazon RDS database instance for storage. It uses the AWS CloudFormation bootstrap scripts to install packages and files at instance launch time. **WARNING** This template creates one or more Amazon EC2 instances, an Elastic Load Balancer and an Amazon RDS database. You will be billed for the AWS resources used if you create a stack from this template.",
5
+
6
+ "Parameters" : {
7
+
8
+ "KeyName": {
9
+ "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances",
10
+ "Type": "String",
11
+ "MinLength": "1",
12
+ "MaxLength": "255",
13
+ "AllowedPattern" : "[\\x20-\\x7E]*",
14
+ "ConstraintDescription" : "can contain only ASCII characters."
15
+ },
16
+
17
+ "InstanceType" : {
18
+ "Description" : "WebServer EC2 instance type",
19
+ "Type" : "String",
20
+ "Default" : "m1.small",
21
+ "ConstraintDescription" : "must be a valid EC2 instance type."
22
+ },
23
+
24
+ "SiteName": {
25
+ "Default": "My Site",
26
+ "Description" : "The name of the Drupal Site",
27
+ "Type": "String"
28
+ },
29
+
30
+ "SiteEMail": {
31
+ "Description" : "EMail for site adminitrator",
32
+ "Type": "String"
33
+ },
34
+
35
+ "SiteAdmin": {
36
+ "Description" : "The Drupal site admin account username",
37
+ "Type": "String",
38
+ "MinLength": "1",
39
+ "MaxLength": "16",
40
+ "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*",
41
+ "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters."
42
+ },
43
+
44
+ "SitePassword": {
45
+ "NoEcho": "true",
46
+ "Description" : "The Drupal site admin account password",
47
+ "Type": "String",
48
+ "MinLength": "1",
49
+ "MaxLength": "41",
50
+ "AllowedPattern" : "[a-zA-Z0-9]*",
51
+ "ConstraintDescription" : "must contain only alphanumeric characters."
52
+ },
53
+
54
+ "DBName": {
55
+ "Default": "drupaldb",
56
+ "Description" : "The Drupal database name",
57
+ "Type": "String",
58
+ "MinLength": "1",
59
+ "MaxLength": "64",
60
+ "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*",
61
+ "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters."
62
+ },
63
+
64
+ "DBUsername": {
65
+ "Default": "admin",
66
+ "NoEcho": "true",
67
+ "Description" : "The Drupal database admin account username",
68
+ "Type": "String",
69
+ "MinLength": "1",
70
+ "MaxLength": "16",
71
+ "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*",
72
+ "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters."
73
+ },
74
+
75
+ "DBPassword": {
76
+ "Default": "password",
77
+ "NoEcho": "true",
78
+ "Description" : "The Drupal database admin account password",
79
+ "Type": "String",
80
+ "MinLength": "8",
81
+ "MaxLength": "41",
82
+ "AllowedPattern" : "[a-zA-Z0-9]*",
83
+ "ConstraintDescription" : "must contain only alphanumeric characters."
84
+ },
85
+
86
+ "DBClass" : {
87
+ "Default" : "db.m1.small",
88
+ "Description" : "Database instance class",
89
+ "Type" : "String",
90
+ "AllowedValues" : [ "db.m1.small", "db.m1.large", "db.m1.xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge" ],
91
+ "ConstraintDescription" : "must select a valid database instance type."
92
+ },
93
+
94
+ "DBAllocatedStorage" : {
95
+ "Default": "5",
96
+ "Description" : "The size of the database (Gb)",
97
+ "Type": "Number",
98
+ "MinValue": "5",
99
+ "MaxValue": "1024",
100
+ "ConstraintDescription" : "must be between 5 and 1024Gb."
101
+ },
102
+
103
+ "MultiAZDatabase": {
104
+ "Default": "true",
105
+ "Description" : "Create a multi-AZ MySQL Amazon RDS database instance",
106
+ "Type": "String",
107
+ "AllowedValues" : [ "true", "false" ],
108
+ "ConstraintDescription" : "must be either true or false."
109
+ },
110
+
111
+ "WebServerCapacity": {
112
+ "Default": "2",
113
+ "Description" : "The initial number of WebServer instances",
114
+ "Type": "Number",
115
+ "MinValue": "1",
116
+ "MaxValue": "5",
117
+ "ConstraintDescription" : "must be between 1 and 5 EC2 instances."
118
+ },
119
+ "SSHLocation" : {
120
+ "Description" : "The IP address range that can be used to SSH to the EC2 instances",
121
+ "Type": "String",
122
+ "MinLength": "9",
123
+ "MaxLength": "18",
124
+ "Default": "0.0.0.0/0",
125
+ "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
126
+ "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
127
+ }
128
+ },
129
+
130
+ "Mappings" : {
131
+ "AWSInstanceType2Arch" : {
132
+ "t1.micro" : { "Arch" : "64" },
133
+ "m1.small" : { "Arch" : "64" },
134
+ "m1.medium" : { "Arch" : "64" },
135
+ "m1.large" : { "Arch" : "64" },
136
+ "m1.xlarge" : { "Arch" : "64" },
137
+ "m2.xlarge" : { "Arch" : "64" },
138
+ "m2.2xlarge" : { "Arch" : "64" },
139
+ "m2.4xlarge" : { "Arch" : "64" },
140
+ "m3.xlarge" : { "Arch" : "64" },
141
+ "m3.2xlarge" : { "Arch" : "64" },
142
+ "c1.medium" : { "Arch" : "64" },
143
+ "c1.xlarge" : { "Arch" : "64" },
144
+ "cc1.4xlarge" : { "Arch" : "64HVM" },
145
+ "cc2.8xlarge" : { "Arch" : "64HVM" },
146
+ "cg1.4xlarge" : { "Arch" : "64HVM" }
147
+ },
148
+
149
+ "AWSRegionArch2AMI" : {
150
+ "us-east-1" : { "32" : "ami-a0cd60c9", "64" : "ami-aecd60c7", "64HVM" : "ami-a8cd60c1" },
151
+ "us-west-2" : { "32" : "ami-46da5576", "64" : "ami-48da5578", "64HVM" : "NOT_YET_SUPPORTED" },
152
+ "us-west-1" : { "32" : "ami-7d4c6938", "64" : "ami-734c6936", "64HVM" : "NOT_YET_SUPPORTED" },
153
+ "eu-west-1" : { "32" : "ami-61555115", "64" : "ami-6d555119", "64HVM" : "ami-67555113" },
154
+ "ap-southeast-1" : { "32" : "ami-220b4a70", "64" : "ami-3c0b4a6e", "64HVM" : "NOT_YET_SUPPORTED" },
155
+ "ap-southeast-2" : { "32" : "ami-8f990eb5", "64" : "ami-95990eaf", "64HVM" : "NOT_YET_SUPPORTED" },
156
+ "ap-northeast-1" : { "32" : "ami-2a19aa2b", "64" : "ami-2819aa29", "64HVM" : "NOT_YET_SUPPORTED" },
157
+ "sa-east-1" : { "32" : "ami-f836e8e5", "64" : "ami-fe36e8e3", "64HVM" : "NOT_YET_SUPPORTED" }
158
+ }
159
+ },
160
+
161
+ "Resources" : {
162
+
163
+ "S3Bucket" : {
164
+ "Type" : "AWS::S3::Bucket",
165
+ "DeletionPolicy" : "Retain"
166
+ },
167
+
168
+ "BucketPolicy" : {
169
+ "Type" : "AWS::S3::BucketPolicy",
170
+ "Properties" : {
171
+ "PolicyDocument": {
172
+ "Version" : "2008-10-17",
173
+ "Id" : "UploadPolicy",
174
+ "Statement" : [{
175
+ "Sid" : "EnableReadWrite",
176
+ "Action" : ["s3:GetObject", "s3:PutObject", "s3:PutObjectACL" ],
177
+ "Effect" : "Allow",
178
+ "Resource" : { "Fn::Join" : ["", ["arn:aws:s3:::", {"Ref" : "S3Bucket"} , "/*"]]},
179
+ "Principal" : { "AWS": {"Fn::GetAtt" : ["S3User", "Arn"]} }
180
+ }]
181
+ },
182
+ "Bucket" : {"Ref" : "S3Bucket"}
183
+ }
184
+ },
185
+
186
+ "S3User" : {
187
+ "Type" : "AWS::IAM::User",
188
+ "Properties" : {
189
+ "Path": "/",
190
+ "Policies": [{
191
+ "PolicyName": "root",
192
+ "PolicyDocument": { "Statement":[{
193
+ "Effect":"Allow",
194
+ "Action":"s3:*",
195
+ "Resource":"*"
196
+ }]}
197
+ }]
198
+ }
199
+ },
200
+
201
+ "S3Keys" : {
202
+ "Type" : "AWS::IAM::AccessKey",
203
+ "Properties" : {
204
+ "UserName" : {"Ref": "S3User"}
205
+ }
206
+ },
207
+
208
+ "ElasticLoadBalancer" : {
209
+ "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
210
+ "Metadata" : {
211
+ "Comment" : "Configure the Load Balancer with a simple health check and cookie-based stickiness"
212
+ },
213
+ "Properties" : {
214
+ "AvailabilityZones" : { "Fn::GetAZs" : "" },
215
+ "LBCookieStickinessPolicy" : [ {
216
+ "PolicyName" : "CookieBasedPolicy",
217
+ "CookieExpirationPeriod" : "30"
218
+ } ],
219
+ "Listeners" : [ {
220
+ "LoadBalancerPort" : "80",
221
+ "InstancePort" : "80",
222
+ "Protocol" : "HTTP",
223
+ "PolicyNames" : [ "CookieBasedPolicy" ]
224
+ } ],
225
+ "HealthCheck" : {
226
+ "Target" : "HTTP:80/",
227
+ "HealthyThreshold" : "2",
228
+ "UnhealthyThreshold" : "5",
229
+ "Interval" : "10",
230
+ "Timeout" : "5"
231
+ }
232
+ }
233
+ },
234
+
235
+ "WebServerGroup" : {
236
+ "Type" : "AWS::AutoScaling::AutoScalingGroup",
237
+ "Properties" : {
238
+ "AvailabilityZones" : { "Fn::GetAZs" : "" },
239
+ "LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
240
+ "MinSize" : "1",
241
+ "MaxSize" : "5",
242
+ "DesiredCapacity" : { "Ref" : "WebServerCapacity" },
243
+ "LoadBalancerNames" : [ { "Ref" : "ElasticLoadBalancer" } ]
244
+ }
245
+ },
246
+
247
+ "LaunchConfig": {
248
+ "Type" : "AWS::AutoScaling::LaunchConfiguration",
249
+ "Metadata" : {
250
+ "AWS::CloudFormation::Init" : {
251
+ "config" : {
252
+ "packages" : {
253
+ "yum" : {
254
+ "httpd" : [],
255
+ "php" : [],
256
+ "php-mysql" : [],
257
+ "php-gd" : [],
258
+ "php-xml" : [],
259
+ "php-mbstring" : [],
260
+ "mysql" : [],
261
+ "gcc" : [],
262
+ "make" : [],
263
+ "libstdc++-devel" : [],
264
+ "gcc-c++" : [],
265
+ "fuse" : [],
266
+ "fuse-devel" : [],
267
+ "libcurl-devel" : [],
268
+ "libxml2-devel" : [],
269
+ "openssl-devel" : [],
270
+ "mailcap" : []
271
+
272
+ }
273
+ },
274
+
275
+ "sources" : {
276
+ "/var/www/html" : "http://ftp.drupal.org/files/projects/drupal-7.8.tar.gz",
277
+ "/home/ec2-user" : "http://ftp.drupal.org/files/projects/drush-7.x-4.5.tar.gz",
278
+ "/home/ec2-user/s3fs" : "http://s3fs.googlecode.com/files/s3fs-1.61.tar.gz"
279
+ },
280
+
281
+ "files" : {
282
+ "/etc/passwd-s3fs" : {
283
+ "content" : { "Fn::Join" : ["", [ { "Ref" : "S3Keys" }, ":", {"Fn::GetAtt": ["S3Keys", "SecretAccessKey"]}, "\n" ]]},
284
+ "mode" : "000400",
285
+ "owner" : "root",
286
+ "group" : "root"
287
+ },
288
+
289
+ "/home/ec2-user/settings.php" : {
290
+ "content" : { "Fn::Join" : ["", [
291
+ "<?php\n",
292
+ "\n",
293
+ "$databases = array (\n",
294
+ " 'default' =>\n",
295
+ " array (\n",
296
+ " 'default' =>\n",
297
+ " array (\n",
298
+ " 'database' => '", { "Ref" : "DBName" }, "',\n",
299
+ " 'username' => '", { "Ref" : "DBUsername" }, "',\n",
300
+ " 'password' => '", { "Ref" : "DBPassword" }, "',\n",
301
+ " 'host' => '", {"Fn::GetAtt" : ["DBInstance", "Endpoint.Address"]}, "',\n",
302
+ " 'port' => '", {"Fn::GetAtt" : ["DBInstance", "Endpoint.Port"]}, "',\n",
303
+ " 'driver' => 'mysql',\n",
304
+ " 'prefix' => 'drupal_',\n",
305
+ " ),\n",
306
+ " ),\n",
307
+ ");\n",
308
+ "\n",
309
+ "$update_free_access = FALSE;\n",
310
+ "\n",
311
+ "$drupal_hash_salt = '0c3R8noNALe3shsioQr5hK1dMHdwRfikLoSfqn0_xpA';\n",
312
+ "\n",
313
+ "ini_set('session.gc_probability', 1);\n",
314
+ "ini_set('session.gc_divisor', 100);\n",
315
+ "ini_set('session.gc_maxlifetime', 200000);\n",
316
+ "ini_set('session.cookie_lifetime', 2000000);\n"
317
+ ]]},
318
+ "mode" : "000400",
319
+ "owner" : "root",
320
+ "group" : "root"
321
+ }
322
+ },
323
+
324
+ "services" : {
325
+ "sysvinit" : {
326
+ "httpd" : { "enabled" : "true", "ensureRunning" : "true" },
327
+ "sendmail" : { "enabled" : "false", "ensureRunning" : "false" }
328
+ }
329
+ }
330
+ }
331
+ }
332
+ },
333
+ "Properties": {
334
+ "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
335
+ { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
336
+ "InstanceType" : { "Ref" : "InstanceType" },
337
+ "SecurityGroups" : [ {"Ref" : "WebServerSecurityGroup"} ],
338
+ "KeyName" : { "Ref" : "KeyName" },
339
+ "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
340
+ "#!/bin/bash -v\n",
341
+ "yum update -y aws-cfn-bootstrap\n",
342
+
343
+ "# Helper function\n",
344
+ "function error_exit\n",
345
+ "{\n",
346
+ " /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '", { "Ref" : "WaitHandle" }, "'\n",
347
+ " exit 1\n",
348
+ "}\n",
349
+
350
+ "# Install Apache Web Server, MySQL and Drupal\n",
351
+ "/opt/aws/bin/cfn-init -s ", { "Ref" : "AWS::StackId" }, " -r LaunchConfig ",
352
+ " --region ", { "Ref" : "AWS::Region" }, " || error_exit 'Failed to run cfn-init'\n",
353
+
354
+ "# Install s3fs\n",
355
+ "cd /home/ec2-user/s3fs/s3fs-1.61\n",
356
+ "./configure --prefix=/usr\n",
357
+ "make\n",
358
+ "make install\n",
359
+
360
+ "# Move the website files to the top level\n",
361
+ "mv /var/www/html/drupal-7.8/* /var/www/html\n",
362
+ "mv /var/www/html/drupal-7.8/.htaccess /var/www/html\n",
363
+ "rm -Rf /var/www/html/drupal-7.8\n",
364
+
365
+ "# Mount the S3 bucket\n",
366
+ "mv /var/www/html/sites/default/files /var/www/html/sites/default/files_original\n",
367
+ "mkdir -p /var/www/html/sites/default/files\n",
368
+ "s3fs -o allow_other -o use_cache=/tmp ", { "Ref" : "S3Bucket" } ," /var/www/html/sites/default/files || error_exit 'Failed to mount the S3 bucket'\n",
369
+ "echo `hostname` >> /var/www/html/sites/default/files/hosts\n",
370
+
371
+ "# Make changes to Apache Web Server configuration\n",
372
+ "sed -i 's/AllowOverride None/AllowOverride All/g' /etc/httpd/conf/httpd.conf\n",
373
+ "service httpd restart\n",
374
+
375
+ "# Only execute the site install if we are the first host up - otherwise we'll end up losing all the data\n",
376
+ "read first < /var/www/html/sites/default/files/hosts\n",
377
+ "if [ `hostname` = $first ]\n",
378
+ "then\n",
379
+ " # Create the site in Drupal\n",
380
+ " cd /var/www/html\n",
381
+ " ~ec2-user/drush/drush site-install standard --yes",
382
+ " --site-name='", { "Ref" : "SiteName" }, "' --site-mail=", { "Ref" : "SiteEMail" },
383
+ " --account-name=", { "Ref" : "SiteAdmin" }, " --account-pass=", { "Ref" : "SitePassword" },
384
+ " --db-url=mysql://", { "Ref" : "DBUsername" }, ":", { "Ref" : "DBPassword" }, "@", {"Fn::GetAtt" : ["DBInstance", "Endpoint.Address"]}, ":", {"Fn::GetAtt" : ["DBInstance", "Endpoint.Port"]}, "/", { "Ref" : "DBName" },
385
+ " --db-prefix=drupal_\n",
386
+ " # use the S3 bucket for shared file storage\n",
387
+ " cp -R sites/default/files_original/* sites/default/files\n",
388
+ " cp -R sites/default/files_original/.htaccess sites/default/files\n",
389
+ "else\n",
390
+ " # Copy settings.php file since everything else is configured\n",
391
+ " cp /home/ec2-user/settings.php /var/www/html/sites/default\n",
392
+ "fi\n",
393
+ "rm /home/ec2-user/settings.php\n",
394
+
395
+ "# All is well so signal success\n",
396
+ "/opt/aws/bin/cfn-signal -e 0 -r \"Drupal setup complete\" '", { "Ref" : "WaitHandle" }, "'\n"
397
+
398
+ ]]}}
399
+ }
400
+ },
401
+
402
+ "WaitHandle" : {
403
+ "Type" : "AWS::CloudFormation::WaitConditionHandle"
404
+ },
405
+
406
+ "WaitCondition" : {
407
+ "Type" : "AWS::CloudFormation::WaitCondition",
408
+ "DependsOn" : "WebServerGroup",
409
+ "Properties" : {
410
+ "Handle" : {"Ref" : "WaitHandle"},
411
+ "Timeout" : "600"
412
+ }
413
+ },
414
+
415
+ "DBInstance" : {
416
+ "Type": "AWS::RDS::DBInstance",
417
+ "Properties": {
418
+ "DBName" : { "Ref" : "DBName" },
419
+ "Engine" : "MySQL",
420
+ "MultiAZ" : { "Ref": "MultiAZDatabase" },
421
+ "MasterUsername" : { "Ref" : "DBUsername" },
422
+ "DBInstanceClass" : { "Ref" : "DBClass" },
423
+ "DBSecurityGroups" : [{ "Ref" : "DBSecurityGroup" }],
424
+ "AllocatedStorage" : { "Ref" : "DBAllocatedStorage" },
425
+ "MasterUserPassword": { "Ref" : "DBPassword" }
426
+ }
427
+ },
428
+
429
+ "DBSecurityGroup": {
430
+ "Type": "AWS::RDS::DBSecurityGroup",
431
+ "Properties": {
432
+ "DBSecurityGroupIngress": { "EC2SecurityGroupName": { "Ref": "WebServerSecurityGroup"} },
433
+ "GroupDescription" : "Frontend Access"
434
+ }
435
+ },
436
+
437
+ "WebServerSecurityGroup" : {
438
+ "Type" : "AWS::EC2::SecurityGroup",
439
+ "Properties" : {
440
+ "GroupDescription" : "Enable HTTP access via port 80, locked down to requests from the load balancer only and SSH access",
441
+ "SecurityGroupIngress" : [
442
+ {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupOwnerId" : {"Fn::GetAtt" : ["ElasticLoadBalancer", "SourceSecurityGroup.OwnerAlias"]},"SourceSecurityGroupName" : {"Fn::GetAtt" : ["ElasticLoadBalancer", "SourceSecurityGroup.GroupName"]}},
443
+ {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "SSHLocation"}}
444
+ ]
445
+ }
446
+ }
447
+ },
448
+
449
+ "Outputs" : {
450
+ "WebsiteURL" : {
451
+ "Value" : { "Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "ElasticLoadBalancer", "DNSName" ]}]] },
452
+ "Description" : "Drupal Website"
453
+ }
454
+ }
455
+ }