rubber 1.0.2

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 (163) hide show
  1. data/CHANGELOG +39 -0
  2. data/COPYING +339 -0
  3. data/README +6 -0
  4. data/TODO +11 -0
  5. data/VERSION +1 -0
  6. data/bin/vulcanize +41 -0
  7. data/generators/vulcanize/USAGE +6 -0
  8. data/generators/vulcanize/templates/apache/config/rubber/deploy-apache.rb +51 -0
  9. data/generators/vulcanize/templates/apache/config/rubber/role/apache/deflate.conf +10 -0
  10. data/generators/vulcanize/templates/apache/config/rubber/role/apache/expires.conf +9 -0
  11. data/generators/vulcanize/templates/apache/config/rubber/role/apache/headers.conf +6 -0
  12. data/generators/vulcanize/templates/apache/config/rubber/role/apache/monit-apache.conf +8 -0
  13. data/generators/vulcanize/templates/apache/config/rubber/role/apache/ports.conf +5 -0
  14. data/generators/vulcanize/templates/apache/config/rubber/role/apache/setenvif.conf +52 -0
  15. data/generators/vulcanize/templates/apache/config/rubber/role/web_tools/tools-apache-vhost.conf +62 -0
  16. data/generators/vulcanize/templates/apache/config/rubber/role/web_tools/tools-apache.auth +7 -0
  17. data/generators/vulcanize/templates/apache/config/rubber/role/web_tools/tools-index.html +30 -0
  18. data/generators/vulcanize/templates/apache/config/rubber/rubber-apache.yml +7 -0
  19. data/generators/vulcanize/templates/apache/templates.yml +1 -0
  20. data/generators/vulcanize/templates/base/Capfile +14 -0
  21. data/generators/vulcanize/templates/base/config/deploy.rb +55 -0
  22. data/generators/vulcanize/templates/base/config/rubber/common/crontab +16 -0
  23. data/generators/vulcanize/templates/base/config/rubber/common/profile.rc +9 -0
  24. data/generators/vulcanize/templates/base/config/rubber/deploy-setup.rb +104 -0
  25. data/generators/vulcanize/templates/base/config/rubber/rubber.yml +241 -0
  26. data/generators/vulcanize/templates/base/lib/tasks/rubber.rake +15 -0
  27. data/generators/vulcanize/templates/base/script/cron-rake +18 -0
  28. data/generators/vulcanize/templates/base/script/cron-runner +18 -0
  29. data/generators/vulcanize/templates/base/script/cron-sh +67 -0
  30. data/generators/vulcanize/templates/base/templates.yml +1 -0
  31. data/generators/vulcanize/templates/complete_mongrel_mysql/config/rubber/role/haproxy/haproxy-mongrel.conf +23 -0
  32. data/generators/vulcanize/templates/complete_mongrel_mysql/config/rubber/role/nginx/nginx-mongrel.conf +113 -0
  33. data/generators/vulcanize/templates/complete_mongrel_mysql/config/rubber/rubber-complete.yml +41 -0
  34. data/generators/vulcanize/templates/complete_mongrel_mysql/templates.yml +6 -0
  35. data/generators/vulcanize/templates/complete_passenger_mysql/config/rubber/role/haproxy/haproxy-passenger.conf +19 -0
  36. data/generators/vulcanize/templates/complete_passenger_mysql/config/rubber/rubber-complete.yml +40 -0
  37. data/generators/vulcanize/templates/complete_passenger_mysql/templates.yml +10 -0
  38. data/generators/vulcanize/templates/cruise/config/rubber/deploy-cruise.rb +72 -0
  39. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/cruise +40 -0
  40. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/my.cnf +165 -0
  41. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/production.rb +8 -0
  42. data/generators/vulcanize/templates/cruise/config/rubber/role/cruise/site_config.rb +76 -0
  43. data/generators/vulcanize/templates/cruise/config/rubber/role/web_tools/cruise-nginx.conf +11 -0
  44. data/generators/vulcanize/templates/cruise/config/rubber/rubber-cruise.yml +18 -0
  45. data/generators/vulcanize/templates/cruise/templates.yml +1 -0
  46. data/generators/vulcanize/templates/haproxy/config/rubber/deploy-haproxy.rb +45 -0
  47. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/haproxy-base.conf +26 -0
  48. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/haproxy-default.conf +8 -0
  49. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/monit-haproxy.conf +9 -0
  50. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/syslog-haproxy.conf +6 -0
  51. data/generators/vulcanize/templates/haproxy/config/rubber/role/haproxy/syslogd-default.conf +17 -0
  52. data/generators/vulcanize/templates/haproxy/config/rubber/role/web_tools/haproxy-nginx.conf +10 -0
  53. data/generators/vulcanize/templates/haproxy/config/rubber/rubber-haproxy.yml +7 -0
  54. data/generators/vulcanize/templates/haproxy/templates.yml +1 -0
  55. data/generators/vulcanize/templates/memcached/config/memcached.yml +28 -0
  56. data/generators/vulcanize/templates/memcached/config/rubber/common/memcached.yml +14 -0
  57. data/generators/vulcanize/templates/memcached/config/rubber/role/memcached/memcached.conf +52 -0
  58. data/generators/vulcanize/templates/memcached/config/rubber/role/memcached/memcached_munin_plugin +249 -0
  59. data/generators/vulcanize/templates/memcached/config/rubber/rubber-memcached.yml +7 -0
  60. data/generators/vulcanize/templates/memcached/templates.yml +1 -0
  61. data/generators/vulcanize/templates/minimal_mysql/templates.yml +7 -0
  62. data/generators/vulcanize/templates/minimal_nodb/templates.yml +6 -0
  63. data/generators/vulcanize/templates/mongrel/config/rubber/deploy-mongrel.rb +75 -0
  64. data/generators/vulcanize/templates/mongrel/config/rubber/role/mongrel/mongrel_cluster.yml +12 -0
  65. data/generators/vulcanize/templates/mongrel/config/rubber/role/mongrel/monit-mongrel.conf +20 -0
  66. data/generators/vulcanize/templates/mongrel/config/rubber/rubber-mongrel.yml +9 -0
  67. data/generators/vulcanize/templates/mongrel/templates.yml +1 -0
  68. data/generators/vulcanize/templates/monit/config/rubber/common/monit-default.conf +15 -0
  69. data/generators/vulcanize/templates/monit/config/rubber/common/monit.conf +251 -0
  70. data/generators/vulcanize/templates/monit/config/rubber/deploy-monit.rb +32 -0
  71. data/generators/vulcanize/templates/monit/config/rubber/role/web_tools/monit-admin-nginx.conf +10 -0
  72. data/generators/vulcanize/templates/monit/config/rubber/rubber-monit.yml +6 -0
  73. data/generators/vulcanize/templates/monit/templates.yml +1 -0
  74. data/generators/vulcanize/templates/munin/config/rubber/common/monit-munin.conf +8 -0
  75. data/generators/vulcanize/templates/munin/config/rubber/common/munin-node.conf +48 -0
  76. data/generators/vulcanize/templates/munin/config/rubber/deploy-munin.rb +46 -0
  77. data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin-nginx.conf +8 -0
  78. data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin-plugins.conf +31 -0
  79. data/generators/vulcanize/templates/munin/config/rubber/role/web_tools/munin.conf +80 -0
  80. data/generators/vulcanize/templates/munin/config/rubber/rubber-munin.yml +8 -0
  81. data/generators/vulcanize/templates/munin/script/munin/example_mysql_query.rb +57 -0
  82. data/generators/vulcanize/templates/munin/script/munin/example_simple.rb +24 -0
  83. data/generators/vulcanize/templates/munin/templates.yml +1 -0
  84. data/generators/vulcanize/templates/mysql/config/rubber/common/database.yml +11 -0
  85. data/generators/vulcanize/templates/mysql/config/rubber/deploy-mysql.rb +156 -0
  86. data/generators/vulcanize/templates/mysql/config/rubber/role/db/crontab +14 -0
  87. data/generators/vulcanize/templates/mysql/config/rubber/role/db/monit-mysql.cnf +10 -0
  88. data/generators/vulcanize/templates/mysql/config/rubber/role/db/my.cnf +167 -0
  89. data/generators/vulcanize/templates/mysql/config/rubber/role/mysql_slave/mysql_slave_munin_plugin +51 -0
  90. data/generators/vulcanize/templates/mysql/config/rubber/rubber-mysql.yml +46 -0
  91. data/generators/vulcanize/templates/mysql/templates.yml +1 -0
  92. data/generators/vulcanize/templates/mysql_cluster/config/rubber/common/mysql_cluster_migrations.rb +13 -0
  93. data/generators/vulcanize/templates/mysql_cluster/config/rubber/deploy-mysql_cluster.rb +173 -0
  94. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_data/my.cnf +15 -0
  95. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_mgm/ndb_mgmd.cnf +39 -0
  96. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_sql/monit-mysql_cluster_sql.cnf +10 -0
  97. data/generators/vulcanize/templates/mysql_cluster/config/rubber/role/mysql_sql/my.cnf +23 -0
  98. data/generators/vulcanize/templates/mysql_cluster/config/rubber/rubber-mysql_cluster.yml +32 -0
  99. data/generators/vulcanize/templates/mysql_cluster/templates.yml +1 -0
  100. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/database.yml +16 -0
  101. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/monit-mysql_proxy.cnf +10 -0
  102. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy +153 -0
  103. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy.conf +10 -0
  104. data/generators/vulcanize/templates/mysql_proxy/config/rubber/common/mysql-proxy.lua +5 -0
  105. data/generators/vulcanize/templates/mysql_proxy/config/rubber/deploy-mysql_proxy.rb +52 -0
  106. data/generators/vulcanize/templates/mysql_proxy/config/rubber/rubber-mysql_proxy.yml +11 -0
  107. data/generators/vulcanize/templates/mysql_proxy/templates.yml +1 -0
  108. data/generators/vulcanize/templates/nginx/config/rubber/deploy-nginx.rb +45 -0
  109. data/generators/vulcanize/templates/nginx/config/rubber/role/nginx/crontab +9 -0
  110. data/generators/vulcanize/templates/nginx/config/rubber/role/nginx/monit-nginx.conf +8 -0
  111. data/generators/vulcanize/templates/nginx/config/rubber/role/nginx/nginx.conf +42 -0
  112. data/generators/vulcanize/templates/nginx/config/rubber/role/web_tools/nginx-tools.conf +55 -0
  113. data/generators/vulcanize/templates/nginx/config/rubber/role/web_tools/tools-index.html +30 -0
  114. data/generators/vulcanize/templates/nginx/config/rubber/role/web_tools/tools-nginx.auth +7 -0
  115. data/generators/vulcanize/templates/nginx/config/rubber/rubber-nginx.yml +10 -0
  116. data/generators/vulcanize/templates/nginx/templates.yml +1 -0
  117. data/generators/vulcanize/templates/passenger/config/rubber/deploy-passenger.rb +37 -0
  118. data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/munin-passenger-sudoers.conf +6 -0
  119. data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/munin-passenger.conf +47 -0
  120. data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/passenger-apache-vhost.conf +46 -0
  121. data/generators/vulcanize/templates/passenger/config/rubber/role/passenger/passenger.conf +10 -0
  122. data/generators/vulcanize/templates/passenger/config/rubber/rubber-passenger.yml +12 -0
  123. data/generators/vulcanize/templates/passenger/templates.yml +1 -0
  124. data/generators/vulcanize/templates/sphinx/config/rubber/common/sphinx.yml +46 -0
  125. data/generators/vulcanize/templates/sphinx/config/rubber/deploy-sphinx.rb +112 -0
  126. data/generators/vulcanize/templates/sphinx/config/rubber/role/sphinx/crontab +11 -0
  127. data/generators/vulcanize/templates/sphinx/config/rubber/role/sphinx/monit-sphinx.conf +10 -0
  128. data/generators/vulcanize/templates/sphinx/config/rubber/rubber-sphinx.yml +6 -0
  129. data/generators/vulcanize/templates/sphinx/templates.yml +1 -0
  130. data/generators/vulcanize/vulcanize_generator.rb +67 -0
  131. data/lib/capistrano/hostcmd.rb +12 -0
  132. data/lib/rubber.rb +38 -0
  133. data/lib/rubber/capistrano.rb +1 -0
  134. data/lib/rubber/cloud.rb +13 -0
  135. data/lib/rubber/cloud/aws.rb +305 -0
  136. data/lib/rubber/cloud/base.rb +16 -0
  137. data/lib/rubber/configuration.rb +47 -0
  138. data/lib/rubber/dns.rb +13 -0
  139. data/lib/rubber/dns/base.rb +69 -0
  140. data/lib/rubber/dns/dyndns.rb +63 -0
  141. data/lib/rubber/dns/nettica.rb +73 -0
  142. data/lib/rubber/dns/zerigo.rb +131 -0
  143. data/lib/rubber/environment.rb +161 -0
  144. data/lib/rubber/generator.rb +197 -0
  145. data/lib/rubber/instance.rb +165 -0
  146. data/lib/rubber/recipes/rubber.rb +89 -0
  147. data/lib/rubber/recipes/rubber/bundles.rb +28 -0
  148. data/lib/rubber/recipes/rubber/deploy.rb +90 -0
  149. data/lib/rubber/recipes/rubber/instances.rb +348 -0
  150. data/lib/rubber/recipes/rubber/load_balancers.rb +44 -0
  151. data/lib/rubber/recipes/rubber/security_groups.rb +189 -0
  152. data/lib/rubber/recipes/rubber/setup.rb +357 -0
  153. data/lib/rubber/recipes/rubber/static_ips.rb +107 -0
  154. data/lib/rubber/recipes/rubber/utils.rb +203 -0
  155. data/lib/rubber/recipes/rubber/volumes.rb +264 -0
  156. data/lib/rubber/tasks/rubber.rb +221 -0
  157. data/lib/rubber/util.rb +37 -0
  158. data/test/environment_test.rb +118 -0
  159. data/test/generator_test.rb +323 -0
  160. data/test/instance_test.rb +93 -0
  161. data/test/test_helper.rb +4 -0
  162. data/test/util_test.rb +16 -0
  163. metadata +274 -0
@@ -0,0 +1,197 @@
1
+ require 'erb'
2
+ require 'find'
3
+ require 'fileutils'
4
+
5
+ module Rubber
6
+ module Configuration
7
+
8
+ # Handles selection and transformation of a set of config files
9
+ # based on the host/role they belong to
10
+ class Generator
11
+ attr_accessor :file_pattern
12
+ attr_accessor :no_post
13
+ attr_accessor :force
14
+ attr_accessor :fake_root
15
+ attr_accessor :stop_on_error_cmd
16
+
17
+ def initialize(config_dir, roles, host, options={})
18
+ @config_dir = config_dir
19
+ @roles = roles.to_a.reverse #First roles take precedence
20
+ @host = host || 'no_host'
21
+ @options=options
22
+ end
23
+
24
+ def run
25
+ config_dirs = []
26
+ config_dirs << "#{@config_dir}/common/**/**"
27
+ @roles.sort.each {|role| config_dirs << "#{@config_dir}/role/#{role}/**/**" }
28
+ config_dirs << "#{@config_dir}/host/#{@host}/**/**"
29
+
30
+ pat = Regexp.new(file_pattern) if file_pattern
31
+
32
+ config_dirs.each do |dir|
33
+ Dir[dir].sort.each do |f|
34
+ next if f =~ /\/(CVS|\.svn)\//
35
+ if File.file?(f) && (! pat || pat.match(f))
36
+ LOGGER.info{"Transforming #{f}"}
37
+ begin
38
+ transform(IO.read(f), @options)
39
+ rescue Exception => e
40
+ lines = e.backtrace.grep(/^\(erb\):([0-9]+)/) {|b| Regexp.last_match(1) }
41
+ LOGGER.error{"Transformation failed for #{f}#{':' + lines.first if lines.first}"}
42
+ LOGGER.error e.message
43
+ exit 1
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ # Transforms the ERB template given in srcfile and writes the result to
51
+ # dest_file (if not nil) before returning it
52
+ def transform(src_data, options={})
53
+ config = ConfigDescriptor.new
54
+
55
+ # for development/test, if we have a fake root, echo any
56
+ # calls to system
57
+ if fake_root
58
+ class << config
59
+ def system(*args)
60
+ puts ("Not running system command during a fake_root transformation: #{args.inspect}")
61
+ end
62
+ def open(*args)
63
+ if args.first && args.first =~ /^|/
64
+ puts ("Not running open/pipe command during a fake_root transformation: #{args.inspect}")
65
+ else
66
+ super
67
+ end
68
+ end
69
+ alias ` system
70
+ alias exec system
71
+ alias fork system
72
+ end
73
+ end
74
+
75
+ config.options = options
76
+ template = ERB.new(src_data, nil, "-")
77
+ result = template.result(config.get_binding())
78
+
79
+ return if config.skip
80
+
81
+ config_path = config.path
82
+
83
+ # for development/test, if we have a fake root, then send config
84
+ # output there, and also put write_cmd output there
85
+ if fake_root
86
+ config_path = "write_cmd_" + config.write_cmd.gsub(/[^a-z0-9_-]/i, '') if config.write_cmd
87
+ config_path = "#{fake_root}/#{config_path}" if config_path
88
+ end
89
+
90
+ if ! config_path && ! (config.read_cmd && config.write_cmd)
91
+ raise "Transformation requires either a output filename or command"
92
+ end
93
+
94
+ reader = config_path || "|#{config.read_cmd}"
95
+ orig = IO.read(reader) rescue ""
96
+
97
+ # When additive is set we need to only replace between our delimiters
98
+ if config.additive
99
+ additive = ["# start rubber #{@host}", "# end rubber #{@host}"] unless additive.is_a? Array
100
+ pat = /#{config.additive[0]}.*#{config.additive[1]}/m
101
+ new = "#{config.additive[0]}#{result}#{config.additive[1]}"
102
+ if orig =~ pat
103
+ result = orig.gsub(pat, new)
104
+ else
105
+ result = orig + new + "\n"
106
+ end
107
+ end
108
+
109
+ # Only do something if the transformed result is different than what
110
+ # is currently in the destination file
111
+ if orig != result || force
112
+ # create dirs as needed
113
+ FileUtils.mkdir_p(File.dirname(config_path)) if config_path
114
+
115
+ # Write a backup of original
116
+ open("#{config_path}.bak", 'w') { |f| f.write(orig) } if config_path
117
+
118
+ # Write out transformed file
119
+ writer = config_path || "|#{config.write_cmd}"
120
+ open(writer, 'w') do |pipe|
121
+ pipe.write(result)
122
+ end
123
+ if config.write_cmd && ! fake_root && $?.exitstatus != 0
124
+ raise "Config command failed execution: #{config.write_cmd}"
125
+ end
126
+
127
+ # Set file permissions and owner if needed
128
+ FileUtils.chmod(config.perms, config_path) if config.perms && config_path
129
+ FileUtils.chown(config.owner, config.group, config_path) if config_path && (config.owner || config.group)
130
+
131
+ # Run post transform command if needed
132
+ if config.post
133
+ if orig == result
134
+ LOGGER.info("Nothing to do, not running post command")
135
+ elsif no_post
136
+ LOGGER.info("Not running post command as no post specified")
137
+ elsif fake_root
138
+ LOGGER.info("Not running post command as a fake root was given: #{config.post}")
139
+ else
140
+ # this lets us abort a script if a command in the middle of it errors out
141
+ # stop_on_error_cmd = "function error_exit { exit 99; }; trap error_exit ERR"
142
+ config.post = "#{stop_on_error_cmd}\n#{config.post}" if stop_on_error_cmd
143
+
144
+ LOGGER.info{"Transformation executing post config command: #{config.post}"}
145
+ LOGGER.info `#{config.post}`
146
+ if $?.exitstatus != 0
147
+ raise "Post command failed execution: #{config.post}"
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+ # Instances of this object are used accept settings from with
157
+ # a config file for when it is transformed by Generator
158
+ class ConfigDescriptor
159
+ # The output path to write the transformed config file to
160
+ attr_accessor :path
161
+ # The command to use for reading the original config file from (e.g. "crontab -l")
162
+ attr_accessor :read_cmd
163
+ # The command to use for piping the transformed config file to (e.g. "crontab -")
164
+ attr_accessor :write_cmd
165
+ # The command to run after generating the config file if it has changed
166
+ attr_accessor :post
167
+ # The owner the output file should have, e.g. "root"
168
+ attr_accessor :owner
169
+ # The group the output file should have, e.g. "system"
170
+ attr_accessor :group
171
+ # The permissions the output file should have, e.g. 0644 (octal, leading zero is significant)
172
+ attr_accessor :perms
173
+ # Sets transformation to be additive, only replaces between given delimiters, e/g/ additive = ["## start", "## end"]
174
+ attr_accessor :additive
175
+ # Lets one dynamically determine if a given file gets skipped during transformation
176
+ attr_accessor :skip
177
+ # use sudo to write the output file
178
+ # attr_accessor :sudo
179
+ # options passed in through code
180
+ attr_accessor :options
181
+
182
+ def get_binding
183
+ binding
184
+ end
185
+
186
+ def rubber_env()
187
+ Rubber::Configuration.rubber_env
188
+ end
189
+
190
+ def rubber_instances()
191
+ Rubber::Configuration.rubber_instances
192
+ end
193
+
194
+ end
195
+
196
+ end
197
+ end
@@ -0,0 +1,165 @@
1
+ require 'yaml'
2
+
3
+ module Rubber
4
+ module Configuration
5
+
6
+ # Contains the ec2 instance configuration defined in instance.yml
7
+ #
8
+ class Instance
9
+ attr_reader :file, :artifacts
10
+ include Enumerable
11
+
12
+ def initialize(file)
13
+ LOGGER.debug{"Reading rubber instances from #{file}"}
14
+ @file = file
15
+ @items = {}
16
+ @artifacts = {'volumes' => {}, 'static_ips' => {}}
17
+ if ENV['FILTER']
18
+ @filters = ENV['FILTER'].split(/\s*,\s*/)
19
+ end
20
+
21
+ if File.exist?(@file)
22
+ item_list = File.open(@file) { |f| YAML.load(f) }
23
+ if item_list
24
+ item_list.each do |i|
25
+ if i.is_a? InstanceItem
26
+ @items[i.name] = i
27
+ elsif i.is_a? Hash
28
+ @artifacts.merge!(i)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def save()
36
+ data = []
37
+ data.push(*@items.values)
38
+ data.push(@artifacts)
39
+ File.open(@file, "w") { |f| f.write(YAML.dump(data)) }
40
+ end
41
+
42
+ def [](name)
43
+ @items[name] || @items[name.gsub(/\..*/, '')]
44
+ end
45
+
46
+ # gets the instances for the given role. If options is nil, all roles
47
+ # match, otherwise the role has to have options that match exactly
48
+ def for_role(role_name, options=nil)
49
+ @items.values.find_all {|ic| ic.roles.any? {|r| r.name == role_name && (! options || r.options == options)}}
50
+ end
51
+
52
+ def filtered()
53
+ @items.values.find_all {|ic| ! @filters || @filters.include?(ic.name)}
54
+ end
55
+
56
+ def all_roles()
57
+ @items.collect {|n, i| i.role_names}.flatten.uniq
58
+ end
59
+
60
+ def add(instance_item)
61
+ @items[instance_item.name] = instance_item
62
+ end
63
+
64
+ def remove(name)
65
+ @items.delete(name)
66
+ end
67
+
68
+ def each(&block)
69
+ @items.values.each &block
70
+ end
71
+
72
+ def size
73
+ @items.size
74
+ end
75
+ end
76
+
77
+ # The configuration for a single instance
78
+ class InstanceItem
79
+ attr_reader :name, :domain, :instance_id, :security_groups
80
+ attr_accessor :roles, :zone
81
+ attr_accessor :external_host, :external_ip
82
+ attr_accessor :internal_host, :internal_ip
83
+ attr_accessor :static_ip, :volumes, :partitions
84
+
85
+ def initialize(name, domain, roles, instance_id, security_group_list=[])
86
+ @name = name
87
+ @domain = domain
88
+ @roles = roles
89
+ @instance_id = instance_id
90
+ @security_groups = security_group_list
91
+ end
92
+
93
+ def full_name
94
+ "#@name.#@domain"
95
+ end
96
+
97
+ def role_names()
98
+ roles.collect {|r| r.name}
99
+ end
100
+ end
101
+
102
+ # The configuration for a single role contained in the list
103
+ # of roles in InstanceItem
104
+ class RoleItem
105
+ attr_reader :name, :options
106
+
107
+ def self.expand_role_dependencies(roles, dependency_map, expanded=[])
108
+ roles = Array(roles)
109
+ roles.each do |role|
110
+ unless expanded.include?(role)
111
+ expanded << role
112
+ needed = dependency_map[role]
113
+ expand_role_dependencies(needed, dependency_map, expanded)
114
+ end
115
+ end
116
+ return expanded
117
+ end
118
+
119
+ def self.parse(str)
120
+ data = str.split(':');
121
+ role = Rubber::Configuration::RoleItem.new(data[0])
122
+ if data[1]
123
+ data[1].split(';').each do |pair|
124
+ p = pair.split('=')
125
+ val = case p[1]
126
+ when 'true' then true
127
+ when 'false' then false
128
+ else p[1] end
129
+ role.options[p[0]] = val
130
+ end
131
+ end
132
+ return role
133
+ end
134
+
135
+ def to_s
136
+ str = @name
137
+ @options.each_with_index do |kv, i|
138
+ str += (i == 0 ? ':' : ';')
139
+ str += "#{kv[0]}=#{kv[1]}"
140
+ end
141
+ return str
142
+ end
143
+
144
+ def initialize(name, options={})
145
+ @name = name
146
+ @options = options || {}
147
+ end
148
+
149
+ def eql?(rhs)
150
+ rhs && @name == rhs.name && @options == rhs.options
151
+ end
152
+ alias == eql?
153
+
154
+ def hash()
155
+ @name.hash
156
+ end
157
+
158
+ def <=>(rhs)
159
+ return @name <=> rhs.name
160
+ end
161
+ end
162
+
163
+ end
164
+ end
165
+
@@ -0,0 +1,89 @@
1
+ # add this plugins lib dir to load path for capistrano
2
+ $:.unshift "#{File.dirname(__FILE__)}/../lib"
3
+ require 'rubygems'
4
+ require "socket"
5
+ require 'resolv'
6
+ require 'enumerator'
7
+ require 'capistrano/hostcmd'
8
+ require 'pp'
9
+ require 'rubber'
10
+
11
+ namespace :rubber do
12
+
13
+ # advise capistrano's task method so that tasks for non-existant roles don't
14
+ # fail when roles isn't defined due to using a FILTER for load_roles
15
+ # If you have a task you need to execute even when there are no
16
+ # roles, you have to use required_task instead of task - see rubber:create
17
+ # as an example of this role bootstrapping problem.
18
+ def allow_optional_tasks(ns)
19
+ class << ns
20
+ alias :required_task :task
21
+ def task(name, options={}, &block)
22
+ required_task(name, options) do
23
+ # define empty roles for the case when a task has a role that we don't define anywhere
24
+ [*options[:roles]].each do |r|
25
+ roles[r] ||= []
26
+ end
27
+
28
+ if find_servers_for_task(current_task).empty?
29
+ logger.info "No servers for task #{name}, skipping"
30
+ next
31
+ end
32
+ block.call
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ allow_optional_tasks(self)
39
+ on :load, "rubber:init"
40
+
41
+ required_task :init do
42
+ # Require cap 2.4 since we depend on bugs that have been fixed
43
+ require 'capistrano/version'
44
+ if Capistrano::Version::MAJOR < 2 || Capistrano::Version::MINOR < 4
45
+ fatal "rubber requires capistrano 2.4.0 or greater"
46
+ end
47
+
48
+ set :rubber_cfg, Rubber::Configuration.get_configuration(RUBBER_ENV)
49
+ set :rubber_env, rubber_cfg.environment.bind()
50
+ set :rubber_instances, rubber_cfg.instance
51
+
52
+ set :cloud, Rubber::Cloud::get_provider(rubber_env.cloud_provider || "aws", rubber_env, self)
53
+
54
+ load_roles() unless rubber_env.disable_auto_roles
55
+ # NOTE: for some reason Capistrano requires you to have both the public and
56
+ # the private key in the same folder, the public key should have the
57
+ # extension ".pub".
58
+ ssh_options[:keys] = rubber_env.cloud_providers[rubber_env.cloud_provider].key_file
59
+ end
60
+
61
+
62
+ # Automatically load and define capistrano roles from instance config
63
+ def load_roles
64
+ top.roles.clear
65
+
66
+ # define empty roles for all known ones so tasks don't fail if a role
67
+ # doesn't exist due to a filter
68
+ all_roles = rubber_instances.all_roles
69
+ all_roles += rubber_cfg.environment.known_roles
70
+ all_roles.uniq!
71
+ all_roles.each {|name| top.roles[name.to_sym] = []}
72
+
73
+ # define capistrano host => role mapping for all instances
74
+ rubber_instances.filtered.each do |ic|
75
+ ic.roles.each do |role|
76
+ opts = Rubber::Util::symbolize_keys(role.options)
77
+ msg = "Auto role: #{role.name.to_sym} => #{ic.full_name}"
78
+ msg << ", #{opts.inspect}" if opts.inspect.size > 0
79
+ logger.info msg
80
+ top.role role.name.to_sym, ic.full_name, opts
81
+ end
82
+ end
83
+ end
84
+
85
+ end
86
+
87
+ Dir[File.join(File.dirname(__FILE__), 'rubber/*.rb')].each do |rubber_part|
88
+ load(rubber_part)
89
+ end