sml-rubber 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. data/COPYING +339 -0
  2. data/README +6 -0
  3. data/TODO +9 -0
  4. data/VERSION +1 -0
  5. data/generators/vulcanize/USAGE +6 -0
  6. data/generators/vulcanize/templates/apache/config/rubber/deploy-apache.rb +45 -0
  7. data/generators/vulcanize/templates/apache/config/rubber/role/web/deflate.conf +10 -0
  8. data/generators/vulcanize/templates/apache/config/rubber/role/web/expires.conf +9 -0
  9. data/generators/vulcanize/templates/apache/config/rubber/role/web/headers.conf +6 -0
  10. data/generators/vulcanize/templates/apache/config/rubber/role/web/setenvif.conf +52 -0
  11. data/generators/vulcanize/templates/apache/config/rubber/role/web/vhost.conf +27 -0
  12. data/generators/vulcanize/templates/apache/config/rubber/rubber-apache.yml +15 -0
  13. data/generators/vulcanize/templates/apache/templates.yml +1 -0
  14. data/generators/vulcanize/templates/base/Capfile +17 -0
  15. data/generators/vulcanize/templates/base/config/deploy.rb +77 -0
  16. data/generators/vulcanize/templates/base/config/rubber/common/crontab +16 -0
  17. data/generators/vulcanize/templates/base/config/rubber/common/profile.rc +9 -0
  18. data/generators/vulcanize/templates/base/config/rubber/deploy-setup.rb +56 -0
  19. data/generators/vulcanize/templates/base/config/rubber/rubber.yml +221 -0
  20. data/generators/vulcanize/templates/base/lib/tasks/rubber.rake +18 -0
  21. data/generators/vulcanize/templates/base/script/cron-rake +18 -0
  22. data/generators/vulcanize/templates/base/script/cron-runner +18 -0
  23. data/generators/vulcanize/templates/base/script/cron-sh +67 -0
  24. data/generators/vulcanize/templates/base/templates.yml +1 -0
  25. data/generators/vulcanize/templates/complete_mysql/templates.yml +6 -0
  26. data/generators/vulcanize/templates/complete_passenger_mysql/templates.yml +8 -0
  27. data/generators/vulcanize/templates/cruise/config/rubber/deploy-cruise.rb +74 -0
  28. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/cruise +40 -0
  29. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/my.cnf +165 -0
  30. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/production.rb +8 -0
  31. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/site_config.rb +76 -0
  32. data/generators/vulcanize/templates/cruise/config/rubber/role/web_tools/cruise-nginx.conf +11 -0
  33. data/generators/vulcanize/templates/cruise/config/rubber/rubber-cruise.yml +18 -0
  34. data/generators/vulcanize/templates/cruise/templates.yml +1 -0
  35. data/generators/vulcanize/templates/haproxy/config/rubber/deploy-haproxy.rb +45 -0
  36. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/haproxy-default.conf +8 -0
  37. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/haproxy.conf +44 -0
  38. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/monit-haproxy.conf +9 -0
  39. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/syslog-haproxy.conf +6 -0
  40. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/syslogd-default.conf +17 -0
  41. data/generators/vulcanize/templates/haproxy/config/rubber/role/web_tools/haproxy-nginx.conf +10 -0
  42. data/generators/vulcanize/templates/haproxy/config/rubber/rubber-haproxy.yml +12 -0
  43. data/generators/vulcanize/templates/haproxy/templates.yml +1 -0
  44. data/generators/vulcanize/templates/memcached/config/memcached.yml +28 -0
  45. data/generators/vulcanize/templates/memcached/config/rubber/common/memcached.yml +14 -0
  46. data/generators/vulcanize/templates/memcached/config/rubber/role/memcached/memcached.conf +52 -0
  47. data/generators/vulcanize/templates/memcached/config/rubber/role/memcached/memcached_munin_plugin +249 -0
  48. data/generators/vulcanize/templates/memcached/config/rubber/rubber-memcached.yml +7 -0
  49. data/generators/vulcanize/templates/memcached/templates.yml +1 -0
  50. data/generators/vulcanize/templates/minimal_mysql/templates.yml +7 -0
  51. data/generators/vulcanize/templates/minimal_nodb/templates.yml +6 -0
  52. data/generators/vulcanize/templates/mongrel/config/rubber/deploy-mongrel.rb +75 -0
  53. data/generators/vulcanize/templates/mongrel/config/rubber/role/app/mongrel_cluster.yml +12 -0
  54. data/generators/vulcanize/templates/mongrel/config/rubber/role/app/monit-mongrel.conf +20 -0
  55. data/generators/vulcanize/templates/mongrel/config/rubber/rubber-mongrel.yml +9 -0
  56. data/generators/vulcanize/templates/mongrel/templates.yml +1 -0
  57. data/generators/vulcanize/templates/monit/config/rubber/common/monit-default.conf +15 -0
  58. data/generators/vulcanize/templates/monit/config/rubber/common/monit.conf +251 -0
  59. data/generators/vulcanize/templates/monit/config/rubber/deploy-monit.rb +32 -0
  60. data/generators/vulcanize/templates/monit/config/rubber/role/web_tools/monit-admin-nginx.conf +10 -0
  61. data/generators/vulcanize/templates/monit/config/rubber/rubber-monit.yml +6 -0
  62. data/generators/vulcanize/templates/monit/templates.yml +1 -0
  63. data/generators/vulcanize/templates/munin/config/rubber/common/monit-munin.conf +8 -0
  64. data/generators/vulcanize/templates/munin/config/rubber/common/munin-node.conf +48 -0
  65. data/generators/vulcanize/templates/munin/config/rubber/deploy-munin.rb +30 -0
  66. data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin-nginx.conf +8 -0
  67. data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin-plugins.conf +31 -0
  68. data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin.conf +80 -0
  69. data/generators/vulcanize/templates/munin/config/rubber/rubber-munin.yml +8 -0
  70. data/generators/vulcanize/templates/munin/script/munin/example_mysql_query.rb +57 -0
  71. data/generators/vulcanize/templates/munin/script/munin/example_simple.rb +24 -0
  72. data/generators/vulcanize/templates/munin/templates.yml +1 -0
  73. data/generators/vulcanize/templates/mysql/config/rubber/common/database.yml +11 -0
  74. data/generators/vulcanize/templates/mysql/config/rubber/deploy-mysql.rb +178 -0
  75. data/generators/vulcanize/templates/mysql/config/rubber/role/db/crontab +14 -0
  76. data/generators/vulcanize/templates/mysql/config/rubber/role/db/monit-mysql.cnf +10 -0
  77. data/generators/vulcanize/templates/mysql/config/rubber/role/db/my.cnf +167 -0
  78. data/generators/vulcanize/templates/mysql/config/rubber/role/mysql_slave/mysql_slave_munin_plugin +51 -0
  79. data/generators/vulcanize/templates/mysql/config/rubber/rubber-mysql.yml +38 -0
  80. data/generators/vulcanize/templates/mysql/templates.yml +1 -0
  81. data/generators/vulcanize/templates/mysql_cluster/config/rubber/common/mysql_cluster_migrations.rb +13 -0
  82. data/generators/vulcanize/templates/mysql_cluster/config/rubber/deploy-mysql_cluster.rb +173 -0
  83. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_data/my.cnf +15 -0
  84. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_mgm/ndb_mgmd.cnf +39 -0
  85. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_sql/monit-mysql_cluster_sql.cnf +10 -0
  86. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_sql/my.cnf +23 -0
  87. data/generators/vulcanize/templates/mysql_cluster/config/rubber/rubber-mysql_cluster.yml +32 -0
  88. data/generators/vulcanize/templates/mysql_cluster/templates.yml +1 -0
  89. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/database.yml +16 -0
  90. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/monit-mysql_proxy.cnf +10 -0
  91. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy +153 -0
  92. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy.conf +10 -0
  93. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy.lua +5 -0
  94. data/generators/vulcanize/templates/mysql_proxy/config/rubber/deploy-mysql_proxy.rb +52 -0
  95. data/generators/vulcanize/templates/mysql_proxy/config/rubber/rubber-mysql_proxy.yml +11 -0
  96. data/generators/vulcanize/templates/mysql_proxy/templates.yml +1 -0
  97. data/generators/vulcanize/templates/nginx/config/rubber/deploy-nginx.rb +45 -0
  98. data/generators/vulcanize/templates/nginx/config/rubber/role/web/crontab +9 -0
  99. data/generators/vulcanize/templates/nginx/config/rubber/role/web/monit-nginx.conf +9 -0
  100. data/generators/vulcanize/templates/nginx/config/rubber/role/web/nginx.conf +133 -0
  101. data/generators/vulcanize/templates/nginx/config/rubber/role/web_tools/index.html +23 -0
  102. data/generators/vulcanize/templates/nginx/config/rubber/role/web_tools/nginx-tools.conf +74 -0
  103. data/generators/vulcanize/templates/nginx/config/rubber/rubber-nginx.yml +33 -0
  104. data/generators/vulcanize/templates/nginx/templates.yml +1 -0
  105. data/generators/vulcanize/templates/passenger/config/rubber/deploy-passenger.rb +27 -0
  106. data/generators/vulcanize/templates/passenger/config/rubber/role/web/passenger.conf +8 -0
  107. data/generators/vulcanize/templates/passenger/config/rubber/rubber-passenger.yml +4 -0
  108. data/generators/vulcanize/templates/passenger/templates.yml +1 -0
  109. data/generators/vulcanize/templates/sphinx/config/rubber/common/sphinx.yml +46 -0
  110. data/generators/vulcanize/templates/sphinx/config/rubber/deploy-sphinx.rb +112 -0
  111. data/generators/vulcanize/templates/sphinx/config/rubber/role/sphinx/crontab +11 -0
  112. data/generators/vulcanize/templates/sphinx/config/rubber/role/sphinx/monit-sphinx.conf +10 -0
  113. data/generators/vulcanize/templates/sphinx/config/rubber/rubber-sphinx.yml +6 -0
  114. data/generators/vulcanize/templates/sphinx/templates.yml +1 -0
  115. data/generators/vulcanize/vulcanize_generator.rb +67 -0
  116. data/lib/capistrano/hostcmd.rb +12 -0
  117. data/lib/rubber.rb +37 -0
  118. data/lib/rubber/capistrano.rb +1 -0
  119. data/lib/rubber/cloud.rb +13 -0
  120. data/lib/rubber/cloud/aws.rb +261 -0
  121. data/lib/rubber/cloud/base.rb +16 -0
  122. data/lib/rubber/configuration.rb +47 -0
  123. data/lib/rubber/dns.rb +13 -0
  124. data/lib/rubber/dns/base.rb +69 -0
  125. data/lib/rubber/dns/dyndns.rb +63 -0
  126. data/lib/rubber/dns/nettica.rb +56 -0
  127. data/lib/rubber/dns/zerigo.rb +121 -0
  128. data/lib/rubber/environment.rb +161 -0
  129. data/lib/rubber/generator.rb +197 -0
  130. data/lib/rubber/instance.rb +113 -0
  131. data/lib/rubber/recipes/rubber.rb +88 -0
  132. data/lib/rubber/recipes/rubber/bundles.rb +28 -0
  133. data/lib/rubber/recipes/rubber/deploy.rb +66 -0
  134. data/lib/rubber/recipes/rubber/instances.rb +298 -0
  135. data/lib/rubber/recipes/rubber/security_groups.rb +149 -0
  136. data/lib/rubber/recipes/rubber/setup.rb +285 -0
  137. data/lib/rubber/recipes/rubber/static_ips.rb +107 -0
  138. data/lib/rubber/recipes/rubber/utils.rb +195 -0
  139. data/lib/rubber/recipes/rubber/volumes.rb +263 -0
  140. data/lib/rubber/tasks/rubber.rb +218 -0
  141. data/lib/rubber/util.rb +33 -0
  142. data/test/environment_test.rb +118 -0
  143. data/test/generator_test.rb +323 -0
  144. data/test/instance_test.rb +38 -0
  145. data/test/test_helper.rb +4 -0
  146. data/test/util_test.rb +16 -0
  147. metadata +246 -0
@@ -0,0 +1,298 @@
1
+ namespace :rubber do
2
+
3
+ desc <<-DESC
4
+ Create a new EC2 instance with the given ALIAS and ROLES
5
+ DESC
6
+ required_task :create do
7
+ instance_alias = get_env('ALIAS', "Instance alias (e.g. web01)", true)
8
+ r = get_env('ROLES', "Instance roles (e.g. web,app,db:primary=true)", true)
9
+ if r == '*'
10
+ instance_roles = rubber_cfg.environment.known_roles
11
+ instance_roles = instance_roles.collect {|role| role == "db" ? "db:primary=true" : role }
12
+ else
13
+ instance_roles = r.split(",")
14
+ end
15
+
16
+ ir = []
17
+ instance_roles.each do |r|
18
+ data = r.split(':');
19
+ role = Rubber::Configuration::RoleItem.new(data[0])
20
+ if data[1]
21
+ data[1].split(';').each do |pair|
22
+ p = pair.split('=')
23
+ val = case p[1]
24
+ when 'true' then true
25
+ when 'false' then false
26
+ else p[1] end
27
+ role.options[p[0]] = val
28
+ end
29
+ end
30
+
31
+ # If user doesn't setup a primary db, then be nice and do it
32
+ if role.name == "db" && role.options["primary"] == nil && rubber_cfg.instance.for_role("db").size == 0
33
+ value = Capistrano::CLI.ui.ask("You do not have a primary db role, should #{instance_alias} be it [y/n]?: ")
34
+ role.options["primary"] = true if value =~ /^y/
35
+ end
36
+
37
+ ir << role
38
+ end
39
+
40
+ create_instance(instance_alias, ir)
41
+ end
42
+
43
+ desc <<-DESC
44
+ Refresh the host data for a EC2 instance with the given ALIAS.
45
+ This is useful to run when rubber:create fails after instance creation
46
+ DESC
47
+ task :refresh do
48
+ instance_alias = get_env('ALIAS', "Instance alias (e.g. web01)", true)
49
+ ENV.delete('ROLES') # so we don't get an error if people leave ROLES in env from :create CLI
50
+ refresh_instance(instance_alias)
51
+ end
52
+
53
+ desc <<-DESC
54
+ Destroy the EC2 instance for the given ALIAS
55
+ DESC
56
+ task :destroy do
57
+ instance_alias = get_env('ALIAS', "Instance alias (e.g. web01)", true)
58
+ ENV.delete('ROLES') # so we don't get an error if people leave ROLES in env from :create CLI
59
+ destroy_instance(instance_alias)
60
+ end
61
+
62
+ desc <<-DESC
63
+ Destroy ALL the EC2 instances for the current env
64
+ DESC
65
+ task :destroy_all do
66
+ rubber_cfg.instance.each do |ic|
67
+ destroy_instance(ic.name)
68
+ end
69
+ end
70
+
71
+ desc <<-DESC
72
+ List all your EC2 instances
73
+ DESC
74
+ required_task :describe do
75
+ results = []
76
+ format = "%-10s %-10s %-10s %-15s %-30s"
77
+ results << format % %w[InstanceID State Zone IP Alias\ (*=unknown)]
78
+
79
+ instances = cloud.describe_instances()
80
+ instances.each do |instance|
81
+ local_alias = find_alias(instance[:external_ip], instance[:id], instance[:state] == 'running')
82
+ results << format % [instance[:id], instance[:state], instance[:zone], instance[:external_ip] || "NoIP", local_alias || "Unknown"]
83
+ end
84
+ results.each {|r| logger.info r}
85
+ end
86
+
87
+ desc <<-DESC
88
+ Describes the availability zones
89
+ DESC
90
+ required_task :describe_zones do
91
+ results = []
92
+ format = "%-20s %-15s"
93
+ results << format % %w[Name State]
94
+
95
+ zones = cloud.describe_availability_zones()
96
+ zones.each do |zone|
97
+ results << format % [zone[:name], zone[:state]]
98
+ end
99
+
100
+ results.each {|r| logger.info r}
101
+ end
102
+
103
+
104
+ set :print_ip_command, "ifconfig eth0 | awk 'NR==2 {print $2}' | awk -F: '{print $2}'"
105
+
106
+ # Creates a new ec2 instance with the given alias and roles
107
+ # Configures aliases (/etc/hosts) on local and remote machines
108
+ def create_instance(instance_alias, instance_roles)
109
+ fatal "Instance already exists: #{instance_alias}" if rubber_cfg.instance[instance_alias]
110
+
111
+ role_names = instance_roles.collect{|x| x.name}
112
+ env = rubber_cfg.environment.bind(role_names, instance_alias)
113
+
114
+ # We need to use security_groups during create, so create them up front
115
+ security_groups = env.assigned_security_groups
116
+ security_group_defns = env.security_groups
117
+ if env.auto_security_groups
118
+ hosts = rubber_cfg.instance.collect{|ic| ic.name } + [instance_alias]
119
+ roles = (rubber_cfg.instance.all_roles + role_names).uniq
120
+ security_groups << instance_alias
121
+ security_groups += role_names
122
+ security_groups.uniq!
123
+ security_group_defns = inject_auto_security_groups(security_group_defns, hosts, roles)
124
+ sync_security_groups(security_group_defns)
125
+ else
126
+ sync_security_groups(security_group_defns)
127
+ end
128
+
129
+ ami = env.cloud_providers[env.cloud_provider].image_id
130
+ ami_type = env.cloud_providers[env.cloud_provider].image_type
131
+ availability_zone = env.availability_zone
132
+ logger.info "Creating instance #{ami}/#{ami_type}/#{security_groups.join(',') rescue 'Default'}/#{availability_zone || 'Default'}"
133
+ instance_id = cloud.create_instance(ami, ami_type, security_groups, availability_zone)
134
+
135
+ logger.info "Instance #{instance_id} created"
136
+
137
+ instance_item = Rubber::Configuration::InstanceItem.new(instance_alias, env.domain, instance_roles, instance_id)
138
+ rubber_cfg.instance.add(instance_item)
139
+ rubber_cfg.instance.save()
140
+
141
+
142
+ print "Waiting for instance to start"
143
+ while true do
144
+ print "."
145
+ sleep 2
146
+ instance = cloud.describe_instances(instance_id).first
147
+
148
+ if instance[:state] == "running"
149
+ print "\n"
150
+ logger.info "Instance running, fetching hostname/ip data"
151
+ instance_item.external_host = instance[:external_host]
152
+ instance_item.external_ip = instance[:external_ip]
153
+ instance_item.internal_host = instance[:internal_host]
154
+ rubber_cfg.instance.save()
155
+
156
+ # setup amazon elastic ips if configured to do so
157
+ setup_static_ips
158
+
159
+ # Need to setup aliases so ssh doesn't give us errors when we
160
+ # later try? to connect to same ip but using alias
161
+ setup_local_aliases
162
+
163
+ # re-load the roles since we may have just defined new ones
164
+ load_roles() unless env.disable_auto_roles
165
+
166
+ # Connect to newly created instance and grab its internal ip
167
+ # so that we can update all aliases
168
+
169
+ task :_get_ip, :hosts => instance_item.external_ip do
170
+ instance_item.internal_ip = capture(print_ip_command).strip
171
+ rubber_cfg.instance.save()
172
+ end
173
+
174
+ # even though instance is running, sometimes ssh hasn't started yet,
175
+ # so retry on connect failure
176
+ begin
177
+ _get_ip
178
+ rescue ConnectionError
179
+ sleep 2
180
+ logger.info "Failed to connect to #{instance_alias} (#{instance_item.external_ip}), retrying"
181
+ retry
182
+ end
183
+
184
+ # Add the aliases for this instance to all other hosts
185
+ setup_remote_aliases
186
+ setup_dns_aliases
187
+
188
+ break
189
+ end
190
+ end
191
+ end
192
+
193
+ # Refreshes a ec2 instance with the given alias
194
+ # Configures aliases (/etc/hosts) on local and remote machines
195
+ def refresh_instance(instance_alias)
196
+ instance_item = rubber_cfg.instance[instance_alias]
197
+
198
+ fatal "Instance does not exist: #{instance_alias}" if ! instance_item
199
+
200
+ env = rubber_cfg.environment.bind(instance_item.role_names, instance_alias)
201
+
202
+ instance = cloud.describe_instance(instance_item.instance_id).first
203
+
204
+ if instance[:state] == "running"
205
+ logger.info "\nInstance running, fetching hostname/ip data"
206
+ instance_item.external_host = instance[:external_host]
207
+ instance_item.external_ip = instance[:external_ip]
208
+ instance_item.internal_host = instance[:internal_host]
209
+
210
+ # Need to setup aliases so ssh doesn't give us errors when we
211
+ # later try to connect to same ip but using alias
212
+ setup_local_aliases
213
+
214
+ # re-load the roles since we may have just defined new ones
215
+ load_roles() unless env.disable_auto_roles
216
+
217
+ # Connect to newly created instance and grab its internal ip
218
+ # so that we can update all aliases
219
+ task :_get_ip, :hosts => instance_item.external_ip do
220
+ instance_item.internal_ip = capture(print_ip_command).strip
221
+ end
222
+ # even though instance is running, we need to give ssh a chance
223
+ # to get started
224
+ sleep 5
225
+ _get_ip
226
+
227
+ # Add the aliases for this instance to all other hosts
228
+ setup_remote_aliases
229
+ setup_dns_aliases
230
+ end
231
+
232
+ rubber_cfg.instance.save()
233
+ end
234
+
235
+
236
+ # Destroys the given ec2 instance
237
+ def destroy_instance(instance_alias)
238
+ instance_item = rubber_cfg.instance[instance_alias]
239
+ fatal "Instance does not exist: #{instance_alias}" if ! instance_item
240
+
241
+ env = rubber_cfg.environment.bind(instance_item.role_names, instance_item.name)
242
+
243
+ value = Capistrano::CLI.ui.ask("About to DESTROY #{instance_alias} (#{instance_item.instance_id}) in mode #{RUBBER_ENV}. Are you SURE [yes/NO]?: ")
244
+ fatal("Exiting", 0) if value != "yes"
245
+
246
+ if instance_item.static_ip
247
+ value = Capistrano::CLI.ui.ask("Instance has a static ip, do you want to release it? [y/N]?: ")
248
+ destroy_static_ip(instance_item.static_ip) if value =~ /^y/
249
+ end
250
+
251
+ if instance_item.volumes
252
+ value = Capistrano::CLI.ui.ask("Instance has persistent volumes, do you want to destroy them? [y/N]?: ")
253
+ if value =~ /^y/
254
+ instance_item.volumes.clone.each do |volume_id|
255
+ destroy_volume(volume_id)
256
+ end
257
+ end
258
+ end
259
+
260
+ logger.info "Destroying instance alias=#{instance_alias}, instance_id=#{instance_item.instance_id}"
261
+
262
+ cloud.destroy_instance(instance_item.instance_id)
263
+
264
+ rubber_cfg.instance.remove(instance_alias)
265
+ rubber_cfg.instance.save()
266
+
267
+ # re-load the roles since we just removed some and setup_remote_aliases
268
+ # shouldn't hit removed ones
269
+ load_roles() unless env.disable_auto_roles
270
+
271
+ setup_aliases
272
+ destroy_dyndns(instance_item)
273
+ cleanup_known_hosts(instance_item) unless env.disable_known_hosts_cleanup
274
+ end
275
+
276
+
277
+ # delete from ~/.ssh/known_hosts all lines that begin with ec2- or instance_alias
278
+ def cleanup_known_hosts(instance_item)
279
+ logger.info "Cleaning ~/.ssh/known_hosts"
280
+ File.open(File.expand_path('~/.ssh/known_hosts'), 'r+') do |f|
281
+ out = ""
282
+ f.each do |line|
283
+ line = case line
284
+ when /^ec2-/; ''
285
+ when /#{instance_item.full_name}/; ''
286
+ when /#{instance_item.external_host}/; ''
287
+ when /#{instance_item.external_ip}/; ''
288
+ else line;
289
+ end
290
+ out << line
291
+ end
292
+ f.pos = 0
293
+ f.print out
294
+ f.truncate(f.pos)
295
+ end
296
+ end
297
+
298
+ end
@@ -0,0 +1,149 @@
1
+ namespace :rubber do
2
+
3
+ desc <<-DESC
4
+ Sets up the network security groups
5
+ All defined groups will be created, and any not defined will be removed.
6
+ Likewise, rules within a group will get created, and those not will be removed
7
+ DESC
8
+ required_task :setup_security_groups do
9
+ env = rubber_cfg.environment.bind()
10
+ security_group_defns = env.security_groups
11
+ if env.auto_security_groups
12
+ hosts = rubber_cfg.instance.collect{|ic| ic.name }
13
+ roles = rubber_cfg.instance.all_roles
14
+ security_group_defns = inject_auto_security_groups(security_group_defns, hosts, roles)
15
+ sync_security_groups(security_group_defns)
16
+ else
17
+ sync_security_groups(security_group_defns)
18
+ end
19
+ end
20
+
21
+ desc <<-DESC
22
+ Describes the network security groups
23
+ DESC
24
+ required_task :describe_security_groups do
25
+ groups = cloud.describe_security_groups()
26
+ groups.each do |group|
27
+ puts "#{group[:name]}, #{group[:description]}"
28
+ group[:permissions].each do |perm|
29
+ puts " protocol: #{perm[:protocol]}"
30
+ puts " from_port: #{perm[:from_port]}"
31
+ puts " to_port: #{perm[:to_port]}"
32
+ puts " source_groups: #{perm[:source_groups].collect {|g| g[:name]}.join(", ") }" if perm[:source_groups]
33
+ puts " source_ips: #{perm[:source_ips].join(", ") }" if perm[:source_ips]
34
+ puts "\n"
35
+ end if group[:permissions]
36
+ puts "\n"
37
+ end
38
+ end
39
+
40
+
41
+ def inject_auto_security_groups(groups, hosts, roles)
42
+ hosts.each do |name|
43
+ group_name = name
44
+ groups[group_name] ||= {'description' => "Rubber automatic security group for host: #{name}", 'rules' => []}
45
+ end
46
+ roles.each do |name|
47
+ group_name = name
48
+ groups[group_name] ||= {'description' => "Rubber automatic security group for role: #{name}", 'rules' => []}
49
+ end
50
+ return groups
51
+ end
52
+
53
+ def sync_security_groups(groups)
54
+ env = rubber_cfg.environment.bind()
55
+ return unless groups
56
+
57
+ groups = Rubber::Util::stringify(groups)
58
+ group_keys = groups.keys.clone()
59
+
60
+ # For each group that does already exist in ec2
61
+ cloud_groups = cloud.describe_security_groups()
62
+ cloud_groups.each do |cloud_group|
63
+ group_name = cloud_group[:name]
64
+ if group_keys.delete(group_name)
65
+ # sync rules
66
+ logger.debug "Security Group already in ec2, syncing rules: #{group_name}"
67
+ group = groups[group_name]
68
+ rules = group['rules'].clone
69
+ rule_maps = []
70
+
71
+ # first collect the rule maps from the request (group/user pairs are duplicated for tcp/udp/icmp,
72
+ # so we need to do this up frnot and remove duplicates before checking against the local rubber rules)
73
+ cloud_group[:permissions].each do |rule|
74
+ if rule[:source_groups]
75
+ rule.source_groups.each do |source_group|
76
+ rule_map = {:source_group_name => source_group[:name], :source_group_account => source_group[:account]}
77
+ rule_map = Rubber::Util::stringify(rule_map)
78
+ rule_maps << rule_map unless rule_maps.include?(rule_map)
79
+ end
80
+ else
81
+ rule_map = Rubber::Util::stringify(rule)
82
+ rule_maps << rule_map unless rule_maps.include?(rule_map)
83
+ end
84
+ end if cloud_group[:permissions]
85
+ # For each rule, if it exists, do nothing, otherwise remove it as its no longer defined locally
86
+ rule_maps.each do |rule_map|
87
+ if rules.delete(rule_map)
88
+ # rules match, don't need to do anything
89
+ # logger.debug "Rule in sync: #{rule_map.inspect}"
90
+ else
91
+ # rules don't match, remove them from ec2 and re-add below
92
+ answer = Capistrano::CLI.ui.ask("Rule '#{rule_map.inspect}' exists in ec2, but not locally, remove from ec2? [y/N]?: ")
93
+ rule_map = Rubber::Util::symbolize_keys(rule_map)
94
+ if rule_map[:source_group_name]
95
+ cloud.remove_security_group_rule(group_name, nil, nil, nil, {:name => rule_map[:source_group_name], :account => rule_map[:source_group_account]})
96
+ else
97
+ rule_map[:source_ips].each do |source_ip|
98
+ cloud.remove_security_group_rule(group_name, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], source_ip)
99
+ end if rule_map[:source_ips] && answer =~ /^y/
100
+ end
101
+ end
102
+ end
103
+
104
+ rules.each do |rule_map|
105
+ # create non-existing rules
106
+ logger.debug "Missing rule, creating: #{rule_map.inspect}"
107
+ rule_map = Rubber::Util::symbolize_keys(rule_map)
108
+ if rule_map[:source_group_name]
109
+ cloud.add_security_group_rule(group_name, nil, nil, nil, {:name => rule_map[:source_group_name], :account => rule_map[:source_group_account]})
110
+ else
111
+ rule_map[:source_ips].each do |source_ip|
112
+ cloud.add_security_group_rule(group_name, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], source_ip)
113
+ end if rule_map[:source_ips]
114
+ end
115
+ end
116
+ else
117
+ # when using auto groups, get prompted too much to delete when
118
+ # switching between production/staging since the hosts aren't shared
119
+ # between the two environments
120
+ if env.force_security_group_cleanup || ! env.auto_security_groups
121
+ # delete group
122
+ answer = Capistrano::CLI.ui.ask("Security group '#{group_name}' exists in ec2 but not locally, remove from ec2? [y/N]: ")
123
+ cloud.destroy_security_group(group_name) if answer =~ /^y/
124
+ end
125
+ end
126
+ end
127
+
128
+ # For each group that didnt already exist in ec2
129
+ group_keys.each do |group_name|
130
+ group = groups[group_name]
131
+ logger.debug "Creating new security group: #{group_name}"
132
+ # create each group
133
+ cloud.create_security_group(group_name, group['description'])
134
+ # create rules for group
135
+ group['rules'].each do |rule_map|
136
+ logger.debug "Creating new rule: #{rule_map.inspect}"
137
+ rule_map = Rubber::Util::symbolize_keys(rule_map)
138
+ if rule_map[:source_group_name]
139
+ cloud.add_security_group_rule(group_name, nil, nil, nil, {:name => rule_map[:source_group_name], :account => rule_map[:source_group_account]})
140
+ else
141
+ rule_map[:source_ips].each do |source_ip|
142
+ cloud.add_security_group_rule(group_name, rule_map[:protocol], rule_map[:from_port], rule_map[:to_port], source_ip)
143
+ end if rule_map[:source_ips]
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ end
@@ -0,0 +1,285 @@
1
+ namespace :rubber do
2
+
3
+ desc <<-DESC
4
+ Bootstraps instances by setting timezone, installing packages and gems
5
+ DESC
6
+ task :bootstrap do
7
+ set_timezone
8
+ link_bash
9
+ install_packages
10
+ setup_volumes
11
+ add_gem_sources
12
+ install_gems
13
+ deploy.setup
14
+ end
15
+
16
+ desc <<-DESC
17
+ Sets up aliases for instance hostnames based on contents of instance.yml.
18
+ Generates /etc/hosts for local/remote machines and sets hostname on
19
+ remote instances, and sets values in dynamic dns entries
20
+ DESC
21
+ required_task :setup_aliases do
22
+ setup_local_aliases
23
+ setup_remote_aliases
24
+ setup_dns_aliases
25
+ end
26
+
27
+ desc <<-DESC
28
+ Sets up local aliases for instance hostnames based on contents of instance.yml.
29
+ Generates/etc/hosts for local machine
30
+ DESC
31
+ required_task :setup_local_aliases do
32
+ hosts_file = '/etc/hosts'
33
+
34
+ # Generate /etc/hosts contents for the local machine from instance config
35
+ env = rubber_cfg.environment.bind()
36
+ delim = "## rubber config #{env.domain} #{RUBBER_ENV}"
37
+ local_hosts = delim + "\n"
38
+ rubber_cfg.instance.each do |ic|
39
+ # don't add unqualified hostname in local hosts file since user may be
40
+ # managing multiple domains with same aliases
41
+ hosts_data = [ic.full_name, ic.external_host, ic.internal_host].join(' ')
42
+ local_hosts << ic.external_ip << ' ' << hosts_data << "\n"
43
+ end
44
+ local_hosts << delim << "\n"
45
+
46
+ # Write out the hosts file for this machine, use sudo
47
+ filtered = File.read(hosts_file).gsub(/^#{delim}.*^#{delim}\n?/m, '')
48
+ logger.info "Writing out aliases into local machines #{hosts_file}, sudo access needed"
49
+ Rubber::Util::sudo_open(hosts_file, 'w') do |f|
50
+ f.write(filtered)
51
+ f.write(local_hosts)
52
+ end
53
+ end
54
+
55
+ desc <<-DESC
56
+ Sets up aliases in dynamic dns provider for instance hostnames based on contents of instance.yml.
57
+ DESC
58
+ required_task :setup_dns_aliases do
59
+ rubber_cfg.instance.each do |ic|
60
+ update_dyndns(ic)
61
+ end
62
+ end
63
+
64
+ desc <<-DESC
65
+ Sets up aliases for instance hostnames based on contents of instance.yml.
66
+ Generates /etc/hosts for remote machines and sets hostname on remote instances
67
+ DESC
68
+ task :setup_remote_aliases do
69
+ hosts_file = '/etc/hosts'
70
+
71
+ # Generate /etc/hosts contents for the remote instance from instance config
72
+ delim = "## rubber config"
73
+ delim = "#{delim} #{RUBBER_ENV}"
74
+ remote_hosts = delim + "\n"
75
+ rubber_cfg.instance.each do |ic|
76
+ hosts_data = [ic.name, ic.full_name, ic.external_host, ic.internal_host].join(' ')
77
+ remote_hosts << ic.internal_ip << ' ' << hosts_data << "\n"
78
+ end
79
+ remote_hosts << delim << "\n"
80
+ if rubber_cfg.instance.size > 0
81
+ # write out the hosts file for the remote instances
82
+ # NOTE that we use "capture" to get the existing hosts
83
+ # file, which only grabs the hosts file from the first host
84
+ filtered = (capture "cat #{hosts_file}").gsub(/^#{delim}.*^#{delim}\n?/m, '')
85
+ filtered = filtered + remote_hosts
86
+ # Put the generated hosts back on remote instance
87
+ put filtered, hosts_file
88
+
89
+ # Setup hostname on instance so shell, etcs have nice display
90
+ sudo "echo $CAPISTRANO:HOST$ > /etc/hostname && hostname $CAPISTRANO:HOST$"
91
+ end
92
+
93
+ # TODO
94
+ # /etc/resolv.conf to add search domain
95
+ # ~/.ssh/options to setup user/host/key aliases
96
+ end
97
+
98
+ desc <<-DESC
99
+ Update to the newest versions of all packages/gems.
100
+ DESC
101
+ task :update do
102
+ upgrade_packages
103
+ update_gems
104
+ end
105
+
106
+ desc <<-DESC
107
+ Upgrade to the newest versions of all Ubuntu packages.
108
+ DESC
109
+ task :upgrade_packages do
110
+ package_helper(true)
111
+ end
112
+
113
+ desc <<-DESC
114
+ Upgrade to the newest versions of all rubygems.
115
+ DESC
116
+ task :update_gems do
117
+ gem_helper(true)
118
+ end
119
+
120
+ desc <<-DESC
121
+ Install extra packages and gems.
122
+ DESC
123
+ task :install do
124
+ install_packages
125
+ install_gems
126
+ end
127
+
128
+ desc <<-DESC
129
+ Install extra Ubuntu packages. Set 'packages' in rubber.yml to \
130
+ be an array of strings.
131
+ DESC
132
+ task :install_packages do
133
+ package_helper(false)
134
+ end
135
+
136
+ desc <<-DESC
137
+ Install extra ruby gems. Set 'gems' in rubber.yml to \
138
+ be an array of strings.
139
+ DESC
140
+ task :install_gems do
141
+ gem_helper(false)
142
+ end
143
+
144
+ desc <<-DESC
145
+ Add extra ruby gems sources. Set 'gemsources' in rubber.yml to \
146
+ be an array of URI strings.
147
+ DESC
148
+ task :add_gem_sources do
149
+ env = rubber_cfg.environment.bind()
150
+ if env.gemsources
151
+ env.gemsources.each { |source| sudo "gem sources -a #{source}"}
152
+ end
153
+ end
154
+
155
+ desc <<-DESC
156
+ The ubuntu has /bin/sh linking to dash instead of bash, fix this
157
+ You can override this task if you don't want this to happen
158
+ DESC
159
+ task :link_bash do
160
+ sudo("ln -sf /bin/bash /bin/sh")
161
+ end
162
+
163
+ desc <<-DESC
164
+ Set the timezone using the value of the variable named timezone. \
165
+ Valid options for timezone can be determined by the contents of \
166
+ /usr/share/zoneinfo, which can be seen here: \
167
+ http://packages.ubuntu.com/cgi-bin/search_contents.pl?searchmode=filelist&word=tzdata&version=gutsy&arch=all&page=1&number=all \
168
+ Remove 'usr/share/zoneinfo/' from the filename, and use the last \
169
+ directory and file as the value. For example 'Africa/Abidjan' or \
170
+ 'posix/GMT' or 'Canada/Eastern'.
171
+ DESC
172
+ task :set_timezone do
173
+ opts = get_host_options('timezone')
174
+ sudo "bash -c 'echo $CAPISTRANO:VAR$ > /etc/timezone'", opts
175
+ sudo "cp /usr/share/zoneinfo/$CAPISTRANO:VAR$ /etc/localtime", opts
176
+ # restart syslog so that times match timezone
177
+ sudo "/etc/init.d/sysklogd restart"
178
+ end
179
+
180
+ def update_dyndns(instance_item)
181
+ env = rubber_cfg.environment.bind(instance_item.role_names, instance_item.name)
182
+ if env.dns_provider
183
+ provider = Rubber::Dns::get_provider(env.dns_provider, env)
184
+ provider.update(instance_item.name, instance_item.external_ip)
185
+ end
186
+ end
187
+
188
+ def destroy_dyndns(instance_item)
189
+ env = rubber_cfg.environment.bind(instance_item.role_names, instance_item.name)
190
+ if env.dns_provider
191
+ provider = Rubber::Dns::get_provider(env.dns_provider, env)
192
+ provider.destroy(instance_item.name)
193
+ end
194
+ end
195
+
196
+ def package_helper(upgrade=false)
197
+ opts = get_host_options('packages') do |pkg_list|
198
+ expanded_pkg_list = []
199
+ pkg_list.each do |pkg_spec|
200
+ if pkg_spec.is_a?(Array)
201
+ expanded_pkg_list << "#{pkg_spec[0]}=#{pkg_spec[1]}"
202
+ else
203
+ expanded_pkg_list << pkg_spec
204
+ end
205
+ end
206
+ expanded_pkg_list.join(' ')
207
+ end
208
+
209
+ sudo "apt-get -q update"
210
+ if upgrade
211
+ sudo "/bin/sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get -q -y --force-yes dist-upgrade'"
212
+ else
213
+ sudo "/bin/sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get -q -y --force-yes install $CAPISTRANO:VAR$'", opts
214
+ end
215
+ end
216
+
217
+ def custom_package(url_base, name, ver, install_test)
218
+ rubber.run_script "install_#{name}", <<-ENDSCRIPT
219
+ if [[ #{install_test} ]]; then
220
+ arch=`uname -m`
221
+ if [ "$arch" = "x86_64" ]; then
222
+ src="#{url_base}/#{name}_#{ver}_amd64.deb"
223
+ else
224
+ src="#{url_base}/#{name}_#{ver}_i386.deb"
225
+ fi
226
+ src_file="${src##*/}"
227
+ wget -qP /tmp ${src}
228
+ dpkg -i /tmp/${src_file}
229
+ fi
230
+ ENDSCRIPT
231
+ end
232
+
233
+ def handle_gem_prompt(ch, data, str)
234
+ ch[:data] ||= ""
235
+ ch[:data] << data
236
+ if data =~ />\s*$/
237
+ logger.info data
238
+ logger.info "The gem command is asking for a number:"
239
+ choice = STDIN.gets
240
+ ch.send_data(choice)
241
+ else
242
+ logger.info data
243
+ end
244
+ end
245
+
246
+ # Helper for installing gems,allows one to respond to prompts
247
+ def gem_helper(update=false)
248
+ cmd = update ? "update" : "install"
249
+
250
+ # when versions are provided for a gem, rubygems fails unless versions ae provided for all gems
251
+ #
252
+ # first do the gems that the user specified versions for
253
+ opts = get_host_options('gems') do |gem_list|
254
+ expanded_gem_list = []
255
+ gem_list.each do |gem_spec|
256
+ if gem_spec.is_a?(Array)
257
+ expanded_gem_list << "#{gem_spec[0]} -v #{gem_spec[1]}"
258
+ end
259
+ end
260
+ expanded_gem_list.join(' ')
261
+ end
262
+ if opts.size > 0
263
+ sudo "gem #{cmd} $CAPISTRANO:VAR$ --no-rdoc --no-ri", opts do |ch, str, data|
264
+ handle_gem_prompt(ch, data, str)
265
+ end
266
+ end
267
+
268
+ # then do the gems without versions
269
+ opts = get_host_options('gems') do |gem_list|
270
+ expanded_gem_list = []
271
+ gem_list.each do |gem_spec|
272
+ if ! gem_spec.is_a?(Array)
273
+ expanded_gem_list << gem_spec
274
+ end
275
+ end
276
+ expanded_gem_list.join(' ')
277
+ end
278
+ if opts.size > 0
279
+ sudo "gem #{cmd} $CAPISTRANO:VAR$ --no-rdoc --no-ri", opts do |ch, str, data|
280
+ handle_gem_prompt(ch, data, str)
281
+ end
282
+ end
283
+ end
284
+
285
+ end