lib/cap-rightscale/configuration/rightscale.rb in cap-rightscale-0.0.12 vs lib/cap-rightscale/configuration/rightscale.rb in cap-rightscale-0.1.0

- old
+ new

@@ -1,5 +1,8 @@ +require 'cap-rightscale/utils/rs_utils.rb' +require 'ping' + module Capistrano class Configuration module RightScale def get_rs_confpath @rs_confpath ||= File.join(ENV['HOME'], ".rsconf", "rsapiconfig.yml") @@ -7,28 +10,27 @@ def set_rs_confpath(path) @rs_confpath = path end + def rs_cache_lifetime(time) + @lifetime = time # seconds + end + + def validate_echo(bool=false) + @pingecho = bool + end + # register deploy host's /etc/hosts OR dns record(replace 's/ #/-000/' to ServerArray name) def use_nickname(bool=false) @use_nick = bool end def domainname(domain) @domain = domain end - def connect - @auth ||= open(get_rs_confpath) {|f| YAML.load(f)} - @conn ||= RightResource::Connection.new do |c| - c.login(:username => @auth["username"], :password => @auth["password"], :account => @auth["account"]) - end - - RightResource::Base.connection = @conn - end - # Get RightScale Server Array # === Parameters # * _role_ - Capistrano role symbol (ex. :app, :web, :db) # * _params[:array_id]_ - ex. :array_id => 1[https://my.rightscale.com/server_arrays/{id}] # * _params[:xxx]_ - ex. :user => "www", :port => 2345, etc... @@ -37,29 +39,50 @@ # server_array :app, :array_id => array_id, :port => 1234 def server_array(role, params) return [] unless check_role(role) raise ArgumentError, ":array_id is not included in params!![#{params}]" unless params.has_key?(:array_id) -start = Time.now - connect logger.info("SETTING ROLE: #{role}") - array = ServerArray.show(params[:array_id]) - logger.info("querying rightscale for server_array #{array.nickname}...") - deployment_name = Deployment.show(array.deployment_href.match(/[0-9]+$/).to_s).nickname - logger.info("Deployment #{deployment_name}:") + # Set rightscale's parameters + _array = params[:array_id] + params.delete(:array_id) # remove rightscale's parameters - host_list = ServerArray.instances(array.id).select {|i| i[:state] == "operational"}.map do |instance| - hostname = instance[:nickname].sub(/ #[0-9]+$/, "-%03d" % instance[:nickname].match(/[0-9]+$/).to_s.to_i) - hostname << ".#{_domain}" if _domain - ip = instance[:private_ip_address] - logger.info("Found server: #{hostname}(#{ip})") - enable_hostname ? hostname : ip - end - role(role, params) { host_list } if host_list + host_list = get_server_cache(role) # Get cache + + if host_list && host_list.size > 0 + logger.info("restore cache of servers:\n#{host_list.pretty_inspect}") + role(role, params) { host_list } # set cache to role() + else + # Request RightScale API +start = Time.now + connect + array = ServerArray.show(_array) + logger.info("querying rightscale for server_array #{array.nickname}...") + deployment_name = Deployment.show(array.deployment_href.match(/[0-9]+$/).to_s).nickname + logger.info("Deployment #{deployment_name}:") + + host_list = ServerArray.instances(array.id).select {|i| i[:state] == "operational"}.map do |instance| + hostname = instance[:nickname].sub(/ #[0-9]+$/, "-%03d" % instance[:nickname].match(/[0-9]+$/).to_s.to_i) + hostname << ".#{_domain}" if _domain + ip = instance[:private_ip_address] + if @pingecho + next unless Ping.pingecho(ip) + end + + logger.info("Found server: #{hostname}(#{ip})") + enable_hostname ? hostname : ip + end + host_list.delete(nil) puts "Time: #{Time.now - start}" + if host_list && host_list.size > 0 + role(role, params) { host_list } + dump_server_cache(role, host_list) # Dump cache + end + end + host_list || [] end # Get servers in deployment # === Parameters @@ -72,31 +95,52 @@ # nickname :db, :name_prefix => "db", :deployment => deployment_id, :user => "mysql" def nickname(role, params) return [] unless check_role(role) raise ArgumentError, ":deployment is not included in params!![#{params}]" unless params.has_key?(:deployment) -start = Time.now - connect logger.info("SETTING ROLE: #{role}") - dept = Deployment.show(params[:deployment], :server_settings => 'true') - logger.info("querying rightscale for servers #{params[:name_prefix]} in deployment #{dept.nickname}...") - srvs = dept.servers.select {|s| s[:state] == "operational"} - srvs = srvs.select {|s| /#{params[:name_prefix]}/ =~ s[:nickname]} if params[:name_prefix] - # remove rightscale's parameters + # Set rightscale's parameters + _dept = params[:deployment] + _name_prefix = params[:name_prefix] + params.delete(:deployment) params.delete(:name_prefix) if params.has_key?(:name_prefix) - host_list = srvs.map do |server| - hostname = server[:nickname] - hostname << ".#{_domain}" if _domain - ip = server[:settings][:private_ip_address] - logger.info("Found server: #{hostname}(#{ip})") - enable_hostname ? hostname : ip - end - role(role, params) { host_list } if host_list + host_list = get_server_cache(role) # Get cache + + if host_list && host_list.size > 0 + logger.info("restore cache of servers:\n#{host_list.pretty_inspect}") + role(role, params) { host_list } # set cache to role() + else + # Request RightScale API +start = Time.now + connect + dept = Deployment.show(_dept, :server_settings => 'true') + logger.info("querying rightscale for servers #{_name_prefix} in deployment #{dept.nickname}...") + srvs = dept.servers.select {|s| s[:state] == "operational"} + srvs = srvs.select {|s| /#{_name_prefix}/ =~ s[:nickname]} if _name_prefix + + host_list = srvs.map do |server| + hostname = server[:nickname] + hostname << ".#{_domain}" if _domain + ip = server[:settings][:private_ip_address] + if @pingecho + next unless Ping.pingecho(ip) + end + + logger.info("Found server: #{hostname}(#{ip})") + enable_hostname ? hostname : ip + end + host_list.delete(nil) puts "Time: #{Time.now - start}" + if host_list && host_list.size > 0 + role(role, params) { host_list } + dump_server_cache(role, host_list) # Dump cache + end + end + host_list || [] end # Get servers matching tags in deployment # === Parameters @@ -110,47 +154,125 @@ def tag(role, params) return [] unless check_role(role) raise ArgumentError, ":tags is not included in params!![#{params}]" unless params.has_key?(:tags) raise ArgumentError, ":deployment is not included in params!![#{params}]" unless params.has_key?(:deployment) -start = Time.now - connect logger.info("SETTING ROLE: #{role}") - dept = Deployment.show(params[:deployment], :server_settings => 'true') - logger.info("querying rightscale for servers matching tags #{params[:tags]} in deployment #{dept.nickname}...") - srvs = dept.servers.select {|s| s[:state] == "operational"} - ts_params = {:resource_type => "ec2_instance", :tags => [params[:tags]]} - ts = Tag.search(ts_params). - select {|s| s.state == "operational"}. - select {|s| s.deployment_href.match(/[0-9]+$/).to_s == params[:deployment].to_s} + # Set rightscale's parameters + _dept = params[:deployment] + _tags = params[:tags] - # diff servers in deployment and servers matching tags in deployment - srvs_ids = srvs.map {|s| s[:href].match(/[0-9]+$/).to_s} - ts_ids = ts.map {|s| s.href.sub("/current", "").match(/[0-9]+$/).to_s} - found_ids = srvs_ids & ts_ids - - # remove rightscale's parameters params.delete(:deployment) params.delete(:tags) - host_list = [] - if found_ids.size > 0 - host_list = srvs.select {|s| found_ids.include?(s[:href].match(/[0-9]+$/).to_s)}.map do |server| - hostname = server[:nickname] - hostname << ".#{_domain}" if _domain - ip = server[:settings][:private_ip_address] - logger.info("Found server: #{hostname}(#{ip})") - enable_hostname ? hostname : ip - end + host_list = get_server_cache(role) # Get cache - role(role, params) { host_list } if host_list - end + if host_list && host_list.size > 0 + logger.info("restore cache of servers:\n#{host_list.pretty_inspect}") + role(role, params) { host_list } # set cache to role() + else + # Request RightScale API +start = Time.now + connect + dept = Deployment.show(_dept, :server_settings => 'true') + logger.info("querying rightscale for servers matching tags #{_tags} in deployment #{dept.nickname}...") + srvs = dept.servers.select {|s| s[:state] == "operational"} + + ts_params = {:resource_type => "ec2_instance", :tags => [_tags]} + ts = Tag.search(ts_params). + select {|s| s.state == "operational"}. + select {|s| s.deployment_href.match(/[0-9]+$/).to_s == _dept.to_s} + + # diff servers in deployment and servers matching tags in deployment + srvs_ids = srvs.map {|s| s[:href].match(/[0-9]+$/).to_s} + ts_ids = ts.map {|s| s.href.sub("/current", "").match(/[0-9]+$/).to_s} + found_ids = srvs_ids & ts_ids + + if found_ids.size > 0 + host_list = srvs.select {|s| found_ids.include?(s[:href].match(/[0-9]+$/).to_s)}.map do |server| + hostname = server[:nickname] + hostname << ".#{_domain}" if _domain + ip = server[:settings][:private_ip_address] + if @pingecho + next unless Ping.pingecho(ip) + end + + logger.info("Found server: #{hostname}(#{ip})") + enable_hostname ? hostname : ip + end + host_list.delete(nil) + end puts "Time: #{Time.now - start}" + if host_list && host_list.size > 0 + role(role, params) { host_list } + dump_server_cache(role, host_list) # Dump cache + end + end + host_list || [] end private + def connect + @auth ||= open(get_rs_confpath) {|f| YAML.load(f)} + @conn ||= RightResource::Connection.new do |c| + c.login(:username => @auth["username"], :password => @auth["password"], :account => @auth["account"]) + end + + RightResource::Base.connection = @conn + end + + def get_server_cache(role) + @lifetime ||= 86400 + @server_cache ||= {} + + begin + @cache_files ||= Dir.glob("#{Dir.tmpdir}/cap-rightscale-#{ENV['USER']}-*/#{stage}*") + + @cache_files.each do |c| + @server_cache.update(Marshal.load(open(c) {|f| f.read})) + end if @cache_files.size > 0 && @server_cache.empty? + + return [] if @server_cache.empty? # No cache entry + + # get servers + if Time.now - @server_cache[role][:cache] > @lifetime + @server_cache.delete(role) + server_list = [] + elsif @server_cache[role][:servers] + server_list = @server_cache[role][:servers] + else + server_list = [] + end + rescue => e + return [] if @server_cache.empty? + end + server_list + end + + def dump_server_cache(role, servers) + h = {role => {:servers => servers, :cache => Time.now}} + cache = @server_cache.update(h) # update servers cache + obj_dump = Marshal.dump(cache) + + # Get cache directory + cache_dir = Dir.glob("#{Dir.tmpdir}/cap-rightscale-#{ENV['USER']}-*").first + if cache_dir.nil? + RSUtils.mk_rs_cache_dir + cache_dir = Dir.glob("#{Dir.tmpdir}/cap-rightscale-#{ENV['USER']}-*").first + exit if cache_dir.nil? + end + cache_file = File.join(cache_dir, stage ? "#{stage}" : "default") + + begin + open(cache_file, "w") {|f| f.write(obj_dump)} + rescue => e + logger.error("#{e.class}: #{e.pretty_inspect}") + logger.debug {"Backtrace:\n#{e.backtrace.pretty_inspect}"} + end + end + def enable_hostname @use_nick ||= false end def _domain