Class: Some
- Inherits:
-
Object
- Object
- Some
- Defined in:
- lib/some.rb
Instance Method Summary collapse
- #api ⇒ Object
- #attach(volume, instance, device) ⇒ Object
- #attached_volumes ⇒ Object
- #available_volumes ⇒ Object
- #bootstrap_chef(hostname) ⇒ Object
- #cache_list ⇒ Object
- #capfile ⇒ Object
- #close_firewall(port) ⇒ Object
- #config ⇒ Object
- #create_keypair ⇒ Object
- #create_security_group ⇒ Object
- #create_volume(vol_id, inst_id) ⇒ Object
- #default_config ⇒ Object
- #delete_keypair ⇒ Object
- #delete_security_group ⇒ Object
- #destroy_volume(volume) ⇒ Object
- #detach(volume) ⇒ Object
- #fetch_list ⇒ Object
- #find(id_or_hostname) ⇒ Object
- #find_keypair ⇒ Object
- #find_security_group ⇒ Object
- #find_security_group_ingress(target) ⇒ Object
- #find_volume(volume_id) ⇒ Object
- #firewall_list ⇒ Object
- #images ⇒ Object
- #instance_info(instance_id) ⇒ Object
- #keypair_file ⇒ Object
- #launch(name = nil, opts = {}) ⇒ Object
- #list ⇒ Object
- #list_by_status(status) ⇒ Object
- #nondestroyed_volumes ⇒ Object
- #open_firewall(port) ⇒ Object
- #pending ⇒ Object
- #read_config ⇒ Object
- #reload ⇒ Object
- #running ⇒ Object
- #server ⇒ Object
- #setup_role(hostname, role, inst_id) ⇒ Object
- #some_dir ⇒ Object
- #ssh(hostname, cmds) ⇒ Object
- #start(instance_id) ⇒ Object
- #stop(instance_id) ⇒ Object
- #stopped ⇒ Object
- #sync ⇒ Object
- #terminate(instance_id) ⇒ Object
- #volumes ⇒ Object
- #wait_for_hostname(instance_id) ⇒ Object
- #wait_for_security_group ⇒ Object
- #wait_for_ssh(hostname) ⇒ Object
- #wait_to_stop(instance_id) ⇒ Object
- #wait_to_terminate(instance_id) ⇒ Object
Instance Method Details
#api ⇒ Object
456 457 458 459 460 461 462 463 |
# File 'lib/some.rb', line 456 def api @api ||= NIFTY::Cloud::Base.new( :access_key => config['access_key'], :secret_key => config['secret_key'], :server => server, :path => '/api' ) end |
#attach(volume, instance, device) ⇒ Object
105 106 107 108 109 110 111 112 |
# File 'lib/some.rb', line 105 def attach(volume, instance, device) result = api.attach_volume( :volume_id => volume, :instance_id => instance, :device => device ) "done" end |
#attached_volumes ⇒ Object
97 98 99 |
# File 'lib/some.rb', line 97 def attached_volumes volumes.select { |vol| vol[:status] == 'in-use' } end |
#available_volumes ⇒ Object
93 94 95 |
# File 'lib/some.rb', line 93 def available_volumes volumes.select { |vol| vol[:status] == 'available' } end |
#bootstrap_chef(hostname) ⇒ Object
280 281 282 283 284 285 286 287 |
# File 'lib/some.rb', line 280 def bootstrap_chef(hostname) commands = [ "curl -L https://www.opscode.com/chef/install.sh | bash", "mkdir -p /var/chef/cookbooks /etc/chef", "echo json_attribs \\'/etc/chef/dna.json\\' > /etc/chef/solo.rb" ] ssh(hostname, commands) end |
#cache_list ⇒ Object
156 157 158 159 160 |
# File 'lib/some.rb', line 156 def cache_list File.open(ENV["HOME"] + "/.some/cache", "w") do |f| f.write(fetch_list.to_yaml) end end |
#capfile ⇒ Object
41 42 43 44 45 46 47 48 |
# File 'lib/some.rb', line 41 def capfile [ %Q(set :user, "#{config["user"]}"), %Q(ssh_options[:keys] = "#{keypair_file}"), %Q(ssh_options[:passphrase] = "#{config["password"]}"), list.map {|inst| %Q(server "#{inst[:public_ip]}", "#{inst[:instance_id]}")} ].flatten.join("\n") end |
#close_firewall(port) ⇒ Object
417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
# File 'lib/some.rb', line 417 def close_firewall(port) target = { :group_name => 'something', :ip_permissions => { :ip_protocol => 'TCP', :in_out => 'IN', :from_port => port, :to_port => port, :cidr_ip => '0.0.0.0/0' } } return unless find_security_group_ingress(target) api.revoke_security_group_ingress(target) end |
#config ⇒ Object
323 324 325 |
# File 'lib/some.rb', line 323 def config @config ||= default_config.merge read_config end |
#create_keypair ⇒ Object
350 351 352 353 354 |
# File 'lib/some.rb', line 350 def create_keypair keypair = api.create_key_pair(:key_name => "something", :password => config['password']).keyMaterial File.open(keypair_file, 'w') { |f| f.write Base64.decode64(keypair) } File.chmod 0600, keypair_file end |
#create_security_group ⇒ Object
366 367 368 369 370 371 372 |
# File 'lib/some.rb', line 366 def create_security_group api.create_security_group(:group_name => 'something', :group_description => 'Something') rescue NIFTY::ResponseError => e if e. != "The groupName 'something' already exists." raise e end end |
#create_volume(vol_id, inst_id) ⇒ Object
119 120 121 122 123 124 125 126 127 128 |
# File 'lib/some.rb', line 119 def create_volume(vol_id, inst_id) result = api.create_volume( :volume_id => vol_id, :instance_id => inst_id, :availability_zone => config['availability_zone'], :size => 1, :accounting_type => 2 ) result["volumeId"] end |
#default_config ⇒ Object
327 328 329 330 331 332 333 334 |
# File 'lib/some.rb', line 327 def default_config { 'user' => 'root', 'ami' => 26, 'availability_zone' => 'west-11', 'password' => 'password' } end |
#delete_keypair ⇒ Object
356 357 358 359 360 |
# File 'lib/some.rb', line 356 def delete_keypair api.delete_key_pair(:key_name => "something") if find_keypair File.unlink(keypair_file) if File.exists? keypair_file "done" end |
#delete_security_group ⇒ Object
385 386 387 388 389 |
# File 'lib/some.rb', line 385 def delete_security_group return unless find_security_group api.delete_security_group(:group_name => 'something') "done" end |
#destroy_volume(volume) ⇒ Object
130 131 132 133 |
# File 'lib/some.rb', line 130 def destroy_volume(volume) api.delete_volume(:volume_id => volume) "done" end |
#detach(volume) ⇒ Object
114 115 116 117 |
# File 'lib/some.rb', line 114 def detach(volume) result = api.detach_volume(:volume_id => volume, :force => "true") "done" end |
#fetch_list ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/some.rb', line 135 def fetch_list return YAML.load File.read(ENV["HOME"] + "/.some/cache") if File.exists?(ENV["HOME"] + "/.some/cache") result = api.describe_instances return [] unless result.reservationSet instances = [] result.reservationSet.item.each do |r| next unless r.groupSet.nil? || r.groupSet.item.first.groupId == 'something' r.instancesSet.item.each do |item| instances << { :instance_id => item.instanceId, :status => item.instanceState.name, :hostname => item.dnsName, :public_ip => item.ipAddress, :private_ip => item.privateIpAddress } end end instances end |
#find(id_or_hostname) ⇒ Object
193 194 195 196 197 198 199 200 |
# File 'lib/some.rb', line 193 def find(id_or_hostname) return unless id_or_hostname id_or_hostname = id_or_hostname.strip.downcase list.detect do |inst| inst[:hostname] == id_or_hostname or inst[:instance_id] == id_or_hostname end end |
#find_keypair ⇒ Object
362 363 364 |
# File 'lib/some.rb', line 362 def find_keypair api.describe_key_pairs.keySet.item.find {|keypair| keypair.keyName == 'something' } end |
#find_security_group ⇒ Object
391 392 393 394 395 396 397 398 399 400 |
# File 'lib/some.rb', line 391 def find_security_group group_info = api.describe_security_groups(:group_name => 'something').securityGroupInfo if group_info group_info.item.find {|group| group.groupName } else nil end rescue NIFTY::ResponseError => e nil end |
#find_security_group_ingress(target) ⇒ Object
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
# File 'lib/some.rb', line 432 def find_security_group_ingress(target) res = api.describe_security_groups security_group = res.securityGroupInfo.item.find {|security_group| security_group.groupName == target[:group_name] } return nil if !security_group || !security_group.ipPermissions security_group.ipPermissions.item.find {|| flag = ( .ipProtocol == target[:ip_permissions][:ip_protocol] && .inOut == target[:ip_permissions][:in_out] ) # also compare from_port when ip_protocol is not ICMP but TCP or UDP if target[:ip_permissions][:ip_protocol] != 'ICMP' flag = flag && (.fromPort == target[:ip_permissions][:from_port].to_s) end if .groups flag = flag && (.groups.item.first.groupName == target[:ip_permissions][:group_name]) else flag = flag && (.ipRanges.item.first.cidrIp == target[:ip_permissions][:cidr_ip]) end flag } end |
#find_volume(volume_id) ⇒ Object
202 203 204 205 206 207 208 209 |
# File 'lib/some.rb', line 202 def find_volume(volume_id) return unless volume_id volume_id = volume_id.strip.downcase volumes.detect do |volume| volume[:volume_id] == volume_id or volume[:volume_id].gsub(/^vol-/, '') == volume_id end end |
#firewall_list ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/some.rb', line 50 def firewall_list security_group = find_security_group return [] if security_group.nil? || security_group.ipPermissions.nil? security_group.ipPermissions.item.map do |row| { :ip_protocol => row["ipProtocol"], :from_port => row["fromPort"], :in_out => row["inOut"], :group => row["groupName"], :cidr => (row["ipRanges"]["item"].first["cidrIp"] rescue nil) } end end |
#images ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/some.rb', line 65 def images result = api.describe_images return [] unless result.imagesSet result.imagesSet.item.map do |row| { :image_id => row["imageId"], :name => row["name"], :availability_zone => row["availabilityZone"] } end end |
#instance_info(instance_id) ⇒ Object
227 228 229 230 231 |
# File 'lib/some.rb', line 227 def instance_info(instance_id) fetch_list.detect do |inst| inst[:instance_id] == instance_id end end |
#keypair_file ⇒ Object
346 347 348 |
# File 'lib/some.rb', line 346 def keypair_file "#{some_dir}/keypair.pem" end |
#launch(name = nil, opts = {}) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/some.rb', line 9 def launch(name=nil, opts={}) ami = opts[:image_id] || config['ami'] raise "No AMI selected" unless ami create_keypair unless File.exists? keypair_file create_security_group wait_for_security_group open_firewall(22) result = api.run_instances( :instance_id => name, :image_id => ami, :instance_type => config['instance_size'] || 'mini', :key_name => 'something', :security_group => 'something', :availability_zone => config['availability_zone'], :disable_api_termination => false, :accounting_type => 2, :agreement => true # for RHEL subscription ) result.instancesSet.item[0].instanceId end |
#list ⇒ Object
33 34 35 |
# File 'lib/some.rb', line 33 def list @list ||= fetch_list end |
#list_by_status(status) ⇒ Object
223 224 225 |
# File 'lib/some.rb', line 223 def list_by_status(status) list.select { |i| i[:status] == status } end |
#nondestroyed_volumes ⇒ Object
101 102 103 |
# File 'lib/some.rb', line 101 def nondestroyed_volumes volumes.select { |vol| vol[:status] != 'deleting' } end |
#open_firewall(port) ⇒ Object
402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
# File 'lib/some.rb', line 402 def open_firewall(port) target = { :group_name => 'something', :ip_permissions => { :ip_protocol => 'TCP', :in_out => 'IN', :from_port => port, :to_port => port, :cidr_ip => '0.0.0.0/0' } } return if find_security_group_ingress(target) api.(target) end |
#pending ⇒ Object
215 216 217 |
# File 'lib/some.rb', line 215 def pending list_by_status('pending') end |
#read_config ⇒ Object
340 341 342 343 344 |
# File 'lib/some.rb', line 340 def read_config YAML.load File.read("#{some_dir}/config.yml") rescue Errno::ENOENT raise "Some is not configured, please fill in ~/.some/config.yml" end |
#reload ⇒ Object
37 38 39 |
# File 'lib/some.rb', line 37 def reload @list = fetch_list end |
#running ⇒ Object
211 212 213 |
# File 'lib/some.rb', line 211 def running list_by_status('running') end |
#server ⇒ Object
465 466 467 468 469 |
# File 'lib/some.rb', line 465 def server zone = config['availability_zone'] host = zone.slice(0, zone.length - 1) "#{host}.cp.cloud.nifty.com" end |
#setup_role(hostname, role, inst_id) ⇒ Object
289 290 291 292 293 294 295 296 297 |
# File 'lib/some.rb', line 289 def setup_role(hostname, role, inst_id) dna = JSON.parse(config['role'][role]) dna.update("some" => {"hostname" => inst_id, "instances" => list}) commands = [ "echo \'#{JSON.pretty_generate(dna)}\' > /etc/chef/dna.json", "chef-solo -r #{config['cookbooks_url']}" ] ssh(hostname, commands) end |
#some_dir ⇒ Object
336 337 338 |
# File 'lib/some.rb', line 336 def some_dir "#{ENV['HOME']}/.some" end |
#ssh(hostname, cmds) ⇒ Object
299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/some.rb', line 299 def ssh(hostname, cmds) STDOUT.puts Net::SSH.start(hostname, config['user'], :keys => [keypair_file], :passphrase => config['password']) do |ssh| File.open("#{ENV['HOME']}/.some/ssh.log", 'w') do |f| ssh.exec!(cmds.join(' && ')) do |ch, stream, data| f.write(data) STDOUT.print data end end end end |
#start(instance_id) ⇒ Object
311 312 313 |
# File 'lib/some.rb', line 311 def start(instance_id) api.start_instances(:instance_id => [ instance_id ]) end |
#stop(instance_id) ⇒ Object
315 316 317 |
# File 'lib/some.rb', line 315 def stop(instance_id) api.stop_instances(:instance_id => [ instance_id ]) end |
#stopped ⇒ Object
219 220 221 |
# File 'lib/some.rb', line 219 def stopped list_by_status('stopped') end |
#sync ⇒ Object
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/some.rb', line 162 def sync # TODO: raise error if ohai is not installed on the server ohai = Hash.new{|h,k| h[k] = ""} list.each do |inst| puts "-----> getting ohai.json from #{inst[:instance_id]}" Net::SSH.start(inst[:hostname], config['user'], :keys => [keypair_file], :passphrase => config['password']) do |ssh| File.open("#{ENV['HOME']}/.some/ssh.log", 'w') do |f| ssh.exec!("mkdir -p /var/chef/data_bags/node && ohai --log_level fatal") do |ch, stream, data| ohai[inst[:instance_id]] += data if stream == :stdout end end end end list.each do |inst| puts "-----> pushing ohai.json list to #{inst[:instance_id]}" Net::SCP.start(inst[:hostname], config['user'], :keys => [keypair_file], :passphrase => config['password']) do |scp| list.each do |inst| json = { "id" => inst[:instance_id], "name" => inst[:instance_id], "chef_environment" => "_default", "json_class" => "Chef::Node", "run_list" => [], "automatic" => JSON.parse(ohai[inst[:instance_id]]) } scp.upload! StringIO.new(JSON.pretty_generate(json)), "/var/chef/data_bags/node/#{inst[:instance_id]}.json" end end end end |
#terminate(instance_id) ⇒ Object
319 320 321 |
# File 'lib/some.rb', line 319 def terminate(instance_id) api.terminate_instances(:instance_id => [ instance_id ]) end |
#volumes ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/some.rb', line 78 def volumes result = api.describe_volumes return [] unless result.volumeSet result.volumeSet.item.map do |row| { :volume_id => row["volumeId"], :size => row["size"], :status => row["status"], :device => (row["attachmentSet"]["item"].first["device"] rescue ""), :instance_id => (row["attachmentSet"]["item"].first["instanceId"] rescue ""), } end end |
#wait_for_hostname(instance_id) ⇒ Object
233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/some.rb', line 233 def wait_for_hostname(instance_id) raise ArgumentError unless instance_id loop do if inst = instance_info(instance_id) if hostname = inst[:hostname] return hostname end end sleep 1 end end |
#wait_for_security_group ⇒ Object
374 375 376 377 378 379 380 381 382 383 |
# File 'lib/some.rb', line 374 def wait_for_security_group loop do if security_group = find_security_group if security_group.groupStatus == 'applied' break end end sleep 5 end end |
#wait_for_ssh(hostname) ⇒ Object
267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/some.rb', line 267 def wait_for_ssh(hostname) raise ArgumentError unless hostname loop do begin Timeout::timeout(4) do TCPSocket.new(hostname, 22) return end rescue SocketError, Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTUNREACH end end end |
#wait_to_stop(instance_id) ⇒ Object
245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/some.rb', line 245 def wait_to_stop(instance_id) raise ArgumentError unless instance_id loop do if inst = instance_info(instance_id) if inst[:status] == 'stopped' break end end sleep 5 end end |
#wait_to_terminate(instance_id) ⇒ Object
257 258 259 260 261 262 263 264 265 |
# File 'lib/some.rb', line 257 def wait_to_terminate(instance_id) raise ArgumentError unless instance_id loop do unless inst = instance_info(instance_id) break end sleep 5 end end |