Class: Maestro::Cloud::Base
- Inherits:
-
Object
- Object
- Maestro::Cloud::Base
- Includes:
- Validator
- Defined in:
- lib/maestro/cloud.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#config_file ⇒ Object
the config file for this cloud.
-
#configurable_nodes ⇒ Object
readonly
the Hash of Configurable Nodes in this Cloud.
-
#log_directory ⇒ Object
readonly
String containing the full path to this Cloud’s log directory.
-
#log_file ⇒ Object
readonly
String containing the full path to this Cloud’s log file.
-
#name ⇒ Object
readonly
the name of this cloud.
Attributes included from Validator
Class Method Summary collapse
-
.create_from_file(config_file) ⇒ Object
Creates a Cloud from the contents of the given file.
Instance Method Summary collapse
-
#chef_solo_installed?(session = nil) ⇒ Boolean
Checks if chef-solo is installed on each of the Configurable Nodes in this Cloud.
-
#configure ⇒ Object
Configures the Nodes in this Cloud.
-
#configure_chef_solo(session = nil) ⇒ Object
configures chef-solo.
-
#initialize(name, cfg_file = nil, &block) ⇒ Base
constructor
Creates a new Cloud object.
-
#install_chef_solo(session = nil) ⇒ Object
installs chef-solo on the Configurable Nodes the given session is set up with.
-
#method_missing(name, *params) ⇒ Object
:nodoc:.
-
#nodes(&block) ⇒ Object
creates the Nodes for this Cloud if a block is given, otherwise returns the Nodes in this Cloud.
-
#nodes=(nodes) ⇒ Object
sets the nodes Hash.
-
#role(name, &block) ⇒ Object
creates a Role.
-
#roles(&block) ⇒ Object
creates the Roles for this Cloud if a block is given.
-
#roles=(roles) ⇒ Object
sets the roles Hash.
-
#run_chef_solo(session = nil) ⇒ Object
runs chef-solo.
-
#shutdown ⇒ Object
Shuts down this Cloud.
-
#start ⇒ Object
Starts this Cloud.
-
#status ⇒ Object
Reports the current status of this Cloud.
Methods included from Validator
#invalidate, #valid?, #validate
Constructor Details
#initialize(name, cfg_file = nil, &block) ⇒ Base
Creates a new Cloud object.
-
name: the name of the Cloud
-
cfg_file: Pointer to the file containing the Cloud configuration (optional)
-
block: contents of the Cloud
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/maestro/cloud.rb', line 33 def initialize(name, cfg_file=nil, &block) super() raise StandardError, "Cloud name cannot contain spaces: #{name}" if name.is_a?(String) && !name.index(/\s/).nil? @name = name @config_file = cfg_file @roles = Hash.new @nodes = Hash.new @configurable_nodes = Hash.new @valid = true @logger = Log4r::Logger.new(Regexp::quote(@name.to_s)) outputter = Log4r::StdoutOutputter.new("#{@name.to_s}-stdout") outputter.formatter = ConsoleFormatter.new @logger.add(outputter) init_logs instance_eval(&block) if block_given? end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *params) ⇒ Object
:nodoc:
94 95 96 97 |
# File 'lib/maestro/cloud.rb', line 94 def method_missing(name, *params) #:nodoc: @valid = false @validation_errors << "Unexpected attribute: #{name}" end |
Instance Attribute Details
#config_file ⇒ Object
the config file for this cloud
20 21 22 |
# File 'lib/maestro/cloud.rb', line 20 def config_file @config_file end |
#configurable_nodes ⇒ Object (readonly)
the Hash of Configurable Nodes in this Cloud
22 23 24 |
# File 'lib/maestro/cloud.rb', line 22 def configurable_nodes @configurable_nodes end |
#log_directory ⇒ Object (readonly)
String containing the full path to this Cloud’s log directory
24 25 26 |
# File 'lib/maestro/cloud.rb', line 24 def log_directory @log_directory end |
#log_file ⇒ Object (readonly)
String containing the full path to this Cloud’s log file
26 27 28 |
# File 'lib/maestro/cloud.rb', line 26 def log_file @log_file end |
#name ⇒ Object (readonly)
the name of this cloud
18 19 20 |
# File 'lib/maestro/cloud.rb', line 18 def name @name end |
Class Method Details
.create_from_file(config_file) ⇒ Object
Creates a Cloud from the contents of the given file
51 52 53 54 55 |
# File 'lib/maestro/cloud.rb', line 51 def self.create_from_file(config_file) cloud = eval(File.read(config_file)) cloud.config_file = config_file return cloud end |
Instance Method Details
#chef_solo_installed?(session = nil) ⇒ Boolean
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/maestro/cloud.rb', line 140 def chef_solo_installed?(session=nil) close_session = false if session.nil? session = open_ssh_session close_session = true end @logger.info "Checking for installation of chef-solo..." valid = true needs_chef = Array.new session.open_channel do |channel| # Find the node for this channel's host the_node = nil @configurable_nodes.each_pair {|name, node| the_node = node if channel[:host].eql? node.hostname} if the_node.nil? @logger.error "Could not find node matching hostname #{channel[:host]}. This should not happen." else channel.request_pty {|ch, success| abort "could not obtain pty" if !success} channel.exec("chef-solo --version") do |ch, success| ch.on_data do |ch, data| if !data.include?("Chef: 0.9") valid = false needs_chef << the_node end end end end end session.loop(60) session.close if close_session return [valid, needs_chef] end |
#configure ⇒ Object
Configures the Nodes in this Cloud
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/maestro/cloud.rb', line 111 def configure @logger.info "Configuring #{@name} Cloud" if !@configurable_nodes.empty? session = open_ssh_session result = chef_solo_installed?(session) if !result[0] names = result[1].collect {|n| n.name} @logger.progress "Installing chef-solo on Nodes #{names.inspect}. This may take a few minutes..." session.close session = open_ssh_session(result[1]) install_chef_solo(session) configure_chef_solo(session) session.close @logger.progress "\n" else @logger.info "chef-solo already installed on Nodes #{@configurable_nodes.keys.inspect}" end @logger.info "Running chef-solo on Nodes #{@configurable_nodes.keys.inspect}. This may take a few minutes..." session = open_ssh_session run_chef_solo(session) session.close @logger.info "Configuration of #{@name} Cloud complete" end end |
#configure_chef_solo(session = nil) ⇒ Object
configures chef-solo
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/maestro/cloud.rb', line 228 def configure_chef_solo(session=nil) close_session = false if session.nil? session = open_ssh_session close_session = true end # write the chef-solo config file chef_solo_config = ["sudo rm /tmp/chef-solo.rb", "sudo mkdir -p /tmp/chef-solo", "sudo mkdir -p /tmp/chef-solo/cookbooks", "sudo mkdir -p /tmp/chef-solo/roles", "sudo sh -c 'echo file_cache_path \\\"/tmp/chef-solo\\\" >> /tmp/chef-solo.rb'", "sudo sh -c 'echo cookbook_path \\\"/tmp/chef-solo/cookbooks\\\" >> /tmp/chef-solo.rb'", "sudo sh -c 'echo role_path \\\"/tmp/chef-solo/roles\\\" >> /tmp/chef-solo.rb'"] chef_solo_config.each do |str| session.open_channel do |channel| channel.request_pty {|ch, success| abort "could not obtain pty" if !success} channel.exec(str) end session.loop(60) end session.close if close_session end |
#install_chef_solo(session = nil) ⇒ Object
installs chef-solo on the Configurable Nodes the given session is set up with
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/maestro/cloud.rb', line 173 def install_chef_solo(session=nil) close_session = false if session.nil? session = open_ssh_session close_session = true end etc_issue = nil session.open_channel do |channel| channel.request_pty {|ch, success| abort "could not obtain pty" if !success} channel.exec("cat /etc/issue") do |ch, success| ch.on_data {|ch, data| etc_issue = data} end end session.loop(60) # shut off the stdout outputter and only log to the nodes' log files @configurable_nodes.each_pair {|name, node| node.disable_stdout} os = Maestro::OperatingSystem.create_from_etc_issue(etc_issue) os.chef_install_script.each do |cmd| session.open_channel do |channel| # Find the node for this channel's host the_node = nil @configurable_nodes.each_pair {|name, node| the_node = node if channel[:host].eql? node.hostname} if the_node.nil? @logger.error "Could not find node matching hostname #{channel[:host]}. This should not happen." else the_node.logger.info "Installing chef-solo" channel.request_pty {|ch, success| abort "could not obtain pty" if !success} channel.exec(cmd) do |ch, success| @logger.progress "." ch.on_data do |ch2, data2| begin the_node.logger.info data2 rescue StandardError => err the_node.logger.error "Unexpected error logging: #{err.to_s}" end end ch.on_extended_data do |ch2, data2| begin the_node.logger.error data2 rescue StandardError => err the_node.logger.error "Unexpected error logging: #{err.to_s}" end end end end end session.loop(60) end # turn the stdout outputter back on @configurable_nodes.each_pair {|name, node| node.enable_stdout} session.close if close_session end |
#nodes(&block) ⇒ Object
creates the Nodes for this Cloud if a block is given, otherwise returns the Nodes in this Cloud
81 82 83 84 85 86 87 |
# File 'lib/maestro/cloud.rb', line 81 def nodes(&block) if block_given? instance_eval(&block) else @nodes end end |
#nodes=(nodes) ⇒ Object
sets the nodes Hash
90 91 92 |
# File 'lib/maestro/cloud.rb', line 90 def nodes=(nodes) @nodes = nodes end |
#role(name, &block) ⇒ Object
creates a Role
72 73 74 75 76 77 78 |
# File 'lib/maestro/cloud.rb', line 72 def role(name, &block) if @roles.has_key?(name) invalidate "Duplicate role definition: #{name}" else @roles[name] = Role.new(name, self, &block) end end |
#roles(&block) ⇒ Object
creates the Roles for this Cloud if a block is given. Otherwise, returns the roles Hash
58 59 60 61 62 63 64 |
# File 'lib/maestro/cloud.rb', line 58 def roles(&block) if block_given? instance_eval(&block) else @roles end end |
#roles=(roles) ⇒ Object
sets the roles Hash
67 68 69 |
# File 'lib/maestro/cloud.rb', line 67 def roles=(roles) @roles = roles end |
#run_chef_solo(session = nil) ⇒ Object
runs chef-solo
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/maestro/cloud.rb', line 254 def run_chef_solo(session=nil) close_session = false if session.nil? session = open_ssh_session close_session = true end # shut off the stdout outputter and only log to the nodes' log files @configurable_nodes.each_pair {|name, node| node.disable_stdout} # clean up existing cookbooks and roles directories if they exist cleanup_cmds = ["sudo rm -rf /tmp/chef-solo/cookbooks", "sudo rm -rf /tmp/chef-solo/roles", "sudo mkdir -p /tmp/chef-solo/cookbooks", "sudo mkdir -p /tmp/chef-solo/roles"] cleanup_cmds.each do |str| session.open_channel do |channel| channel.request_pty {|ch, success| abort "could not obtain pty" if !success} channel.exec(str) end session.loop(60) end # run chef-solo chef_solo_commands = ["sudo chef-solo -l debug -c /tmp/chef-solo.rb -r '#{chef_assets_url()}'"] chef_solo_commands.each do |cmd| session.open_channel do |channel| channel.request_pty {|ch, success| abort "could not obtain pty" if !success} # Find the node for this channel's host the_node = nil @configurable_nodes.each_pair {|name, node| the_node = node if channel[:host].eql? node.hostname} if the_node.nil? @logger.error "Could not find node matching hostname #{channel[:host]}. This should not happen." else node_cmd = cmd + " -j '#{node_json_url(the_node)}'" channel.exec(node_cmd) do |ch, success| ch.on_data do |ch2, data2| begin the_node.logger.info data2 rescue StandardError => err the_node.logger.error "Unexpected error logging: #{err.to_s}" end end ch.on_extended_data do |ch2, data2| begin the_node.logger.error data2 rescue StandardError => err the_node.logger.error "Unexpected error logging: #{err.to_s}" end end end end end session.loop(60) end # turn the stdout outputter back on @configurable_nodes.each_pair {|name, node| node.enable_stdout} session.close if close_session end |
#shutdown ⇒ Object
Shuts down this Cloud. Takes no action if the Cloud is not running
314 315 316 |
# File 'lib/maestro/cloud.rb', line 314 def shutdown @logger.info "Shutting down #{@name} Cloud" end |
#start ⇒ Object
Starts this Cloud. Takes no action if the Cloud is already running as currently configured
106 107 108 |
# File 'lib/maestro/cloud.rb', line 106 def start @logger.info "Starting #{@name} Cloud. This may take a few minutes..." end |
#status ⇒ Object
Reports the current status of this Cloud
100 101 102 103 |
# File 'lib/maestro/cloud.rb', line 100 def status @logger.info "#{@name} Cloud status:" node_statuses end |