sml-rubber 0.9.1

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.
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