Skip to content

Commit

Permalink
Merge pull request #16419 from ailisp/compatible-to-old-app-name
Browse files Browse the repository at this point in the history
some production enhancement to pg_inspector
  • Loading branch information
gtanzillo authored Dec 11, 2017
2 parents 55cde62 + cd46ecf commit ef211a1
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 17 deletions.
19 changes: 19 additions & 0 deletions spec/tools/pg_inspector/active_connections_to_human_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
$LOAD_PATH << Rails.root.join("tools")

require 'pg_inspector'

describe PgInspector::ActiveConnectionsHumanYAML do
it "#compress_id" do
subject = described_class.new
expect(subject.send(:compress_id, 5)).to eq("5")
expect(subject.send(:compress_id, 1_000_000_000_005)).to eq("1r5")
expect(subject.send(:compress_id, 2_000_000_000_005)).to eq("2r5")
end

it "#uncompress_id" do
subject = described_class.new
expect(subject.send(:uncompress_id, "5")).to eq(5)
expect(subject.send(:uncompress_id, "1r5")).to eq(1_000_000_000_005)
expect(subject.send(:uncompress_id, "2r5")).to eq(2_000_000_000_005)
end
end
87 changes: 76 additions & 11 deletions tools/pg_inspector/active_connections_to_human.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
require 'trollop'
require 'yaml'
require 'time'
require 'activerecord-id_regions'
begin
require 'activerecord-id_regions'
rescue LoadError
$old_version = true
end
require 'pg_inspector/error'
require 'pg_inspector/pg_inspector_operation'
require 'pg_inspector/util'

module PgInspector
class ActiveConnectionsHumanYAML < PgInspectorOperation
COMPRESSED_ID_SEPARATOR = 'r'.freeze
DEFAULT_RAILS_SEQUENCE_FACTOR = 1_000_000_000_000
RE_COMPRESSED_ID = /^(\d+)#{COMPRESSED_ID_SEPARATOR}(\d+)$/

HELP_MSG_SHORT = "Dump active connections to human readable YAML file".freeze
def parse_options(args)
self.options = Trollop.options(args) do
Expand Down Expand Up @@ -135,16 +143,30 @@ def push_other_process(result, activity)
result
end

def server_activity?(activity)
miq_activity?(activity) && activity["application_name"].split("|")[3] == "-"
def old_application_name?(activity)
activity["application_name"].start_with?("MIQ ")
end

def worker_activity?(activity)
miq_activity?(activity) && activity["application_name"].split("|")[3] != "-"
def new_application_name?(activity)
activity["application_name"].start_with?("MIQ|")
end

def miq_activity?(activity)
activity["application_name"].start_with?("MIQ")
def server_activity?(activity)
if new_application_name?(activity) && activity["application_name"].split("|")[3] == "-"
return true
elsif old_application_name?(activity) && activity["application_name"].include?(" Server")
return true
end
false
end

def worker_activity?(activity)
if new_application_name?(activity) && activity["application_name"].split("|")[3] != "-"
return true
elsif old_application_name?(activity) && !activity["application_name"].include?(" Server")
return true
end
false
end

def process_activity_shared(activity)
Expand Down Expand Up @@ -172,12 +194,27 @@ def to_utc(time_str)
end

def process_miq_activity_application_name(activity)
# Previous format, before https://github.com/ManageIQ/manageiq/pull/15545
# For server:
# MIQ <pid> Server[<server_compressed_id>], <zone.name>[<zone.compressed_id>]
# For worker:
# MIQ <pid> <minimal_worker_class_name>[<worker_compressed_id>], s[<server_compressed_id>], <zone.name>[<zone.compressed_id>]
# Current :application_name format:
# MIQ|<pid>|<server_id>|<worker_id>|<zone_id>|<class_name>|<zone_name>
# Both previous and current is truncated up to 64 characters
if activity["application_name"].end_with?("...")
$stderr.puts("Warning: the application_name #{activity["application_name"]} is incomplete.")
end
_, pid, server_id, worker_id, zone_id, class_name, zone_name = activity["application_name"].split("|")
if new_application_name?(activity)
_, pid, server_id, worker_id, zone_id, class_name, zone_name = activity["application_name"].split("|")
elsif activity["application_name"].include?(" Server")
# old application name, server activity
_, pid, class_name, server_id, zone_name, zone_id = activity["application_name"].split(/[, \[\]]+/)
worker_id = "-"
else
# old application name, worker activity
_, pid, class_name, worker_id, _, server_id, zone_name, zone_id = activity["application_name"].split(/[, \[\]]+/)
end
activity["pid"] = pid.to_i
activity["class_name"] = class_name
activity["server_id"] = uncompress_id(server_id)
Expand Down Expand Up @@ -206,12 +243,40 @@ def process_miq_server(server)
end
end

def rails_sequence_factor
DEFAULT_RAILS_SEQUENCE_FACTOR
end

def id_to_region(id)
id.to_i / rails_sequence_factor
end

def split_id(id)
id = uncompress_id(id)

region_number = id_to_region(id)
short_id = region_number.zero? ? id : id % (region_number * rails_sequence_factor)

return region_number, short_id
end

def compress_id(id)
Class.new.include(ActiveRecord::IdRegions).compress_id(id)
if $old_version
return nil if id.nil?
region_number, short_id = split_id(id)
region_number.zero? ? short_id.to_s : "#{region_number}#{COMPRESSED_ID_SEPARATOR}#{short_id}"
else
Class.new.include(ActiveRecord::IdRegions).compress_id(id)
end
end

def uncompress_id(id)
Class.new.include(ActiveRecord::IdRegions).uncompress_id(id)
if $old_version
return nil if id.nil?
id.to_s =~ RE_COMPRESSED_ID ? ($1.to_i * rails_sequence_factor + $2.to_i) : id.to_i
else
Class.new.include(ActiveRecord::IdRegions).uncompress_id(id)
end
end

def merge_activity_and_server_info(stat_activities, servers)
Expand All @@ -220,7 +285,7 @@ def merge_activity_and_server_info(stat_activities, servers)
)
servers.each do |server|
server_activities[server["server_id"]] =
server_activities[server["server_id"]].merge(server)
server_activities.fetch(server["server_id"], {}).merge(server)
end
stat_activities["servers"] = hash_val_array(server_activities)
stat_activities
Expand Down
2 changes: 1 addition & 1 deletion tools/pg_inspector/active_connections_to_yaml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def filter_by_application_name(rows_array)

rows_array.each do |row|
next unless row["application_name"].end_with?('..')
error_msg = "The application name for MIQ server/worker: {#app_name} is truncated"
error_msg = "The application name for MIQ server/worker: #{row["application_name"]} is truncated"
if options[:ignore_error]
$stderr.puts error_msg
else
Expand Down
13 changes: 12 additions & 1 deletion tools/pg_inspector/connection_locks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
module PgInspector
class LockConnectionYAML < PgInspectorOperation
HELP_MSG_SHORT = "Dump lock friendly connection information to YAML file".freeze
attr_accessor :locks, :connections
attr_accessor :locks, :connections, :blocked_connections

def parse_options(args)
self.options = Trollop.options(args) do
Expand All @@ -17,6 +17,8 @@ def parse_options(args)
:type => :string, :short => "c", :default => DEFAULT_OUTPUT_PATH.join("#{PREFIX}human.yml").to_s)
opt(:output, "Output file",
:type => :string, :short => "o", :default => DEFAULT_OUTPUT_PATH.join("#{PREFIX}locks_output.yml").to_s)
opt(:output_blocked, "Output blocked connections file",
:type => :string, :short => "b", :default => DEFAULT_OUTPUT_PATH.join("#{PREFIX}locks_output_blocked_connections.yml").to_s)
end
end

Expand All @@ -29,17 +31,26 @@ def run
"Lock friendly connection info",
options[:output]
)
unless blocked_connections.empty?
Util.dump_to_yml_file(
blocked_connections,
"Blocked connections",
options[:output_blocked]
)
end
end

private

def merge_lock_and_connection
some_connection_blocked = false
self.blocked_connections = []
connections["connections"].each do |conn|
conn["blocked_by"] = find_lock_blocking_spid(conn["spid"])
unless conn["blocked_by"].empty?
some_connection_blocked = true
puts "Connection #{conn["spid"]} is blocked by #{conn["blocked_by"]}."
blocked_connections << {conn["spid"] => conn["blocked_by"]}
end
end
unless some_connection_blocked
Expand Down
37 changes: 37 additions & 0 deletions tools/pg_inspector/inspect_pg.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env ruby

## Run pg_inspector using parameters given in local database.yml and v2 key.

if __FILE__ == $PROGRAM_NAME
$LOAD_PATH.push(File.expand_path(File.join(__dir__, %w(.. .. lib))))
end

require 'yaml'
require 'manageiq-gems-pending'
require 'util/miq-password'

BASE_DIR = __dir__
LOG_DIR = '/var/www/miq/vmdb/log'.freeze
DATABASE_YML_FILE_PATH = "#{BASE_DIR}/../../config/database.yml".freeze
V2_KEY_FILE_PATH = "#{BASE_DIR}/../../certs/v2_key".freeze

production_db = YAML.load_file(DATABASE_YML_FILE_PATH)["production"]

db_user = production_db["username"]
db_password_encrypt = production_db["password"]
db_password = MiqPassword.try_decrypt(db_password_encrypt)
db_host = production_db["host"]

# system "#{BASE_DIR}/../pg_inspector.rb -h"
ENV['PGPASSWORD'] = db_password
system("#{BASE_DIR}/../pg_inspector.rb connections -u #{db_user} -s #{db_host} -i")
if File.exist?(Pathname.new(LOG_DIR).join('pg_inspector_server.yml'))
puts("pg_inspector_server.yml already exists, skip generating.")
else
system("#{BASE_DIR}/../pg_inspector.rb servers -u #{db_user} -s #{db_host}")
end
system("#{BASE_DIR}/../pg_inspector.rb human")
success = system("#{BASE_DIR}/../pg_inspector.rb locks")
unless success
exit(1)
end
5 changes: 1 addition & 4 deletions tools/pg_inspector/inspect_pg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ basedir=$(dirname $0)
logdir=/var/www/miq/vmdb/log
logfile=${logdir}/pg_inspector.log
# default postgresql password: smartvm
export PGPASSWORD="${PGPASSWORD:-smartvm}"

# show message on screen and also append to log file
exec > >(tee -ia ${logfile})
Expand All @@ -14,9 +13,7 @@ echo ""
echo "inspect_pg runs on $(date)"

# Run step 1, 3 and 4 in sequence, assume step 2 has done before.
${basedir}/../pg_inspector.rb connections
${basedir}/../pg_inspector.rb human
${basedir}/../pg_inspector.rb locks
bundle exec ${basedir}/inspect_pg.rb

# remove first only if all steps success
if [ $? -ne '0' ]; then
Expand Down
28 changes: 28 additions & 0 deletions tools/pg_inspector/inspect_pg_server.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env ruby
require 'bundler/setup'

## Run pg_inspector servers using parameters given in local database.yml and v2 key.

if __FILE__ == $PROGRAM_NAME
$LOAD_PATH.push(File.expand_path(File.join(__dir__, %w(.. .. lib))))
end

require 'yaml'
require 'manageiq-gems-pending'
require 'util/miq-password'

BASE_DIR = __dir__
LOG_DIR = '/var/www/miq/vmdb/log'.freeze
DATABASE_YML_FILE_PATH = "#{BASE_DIR}/../../config/database.yml".freeze
V2_KEY_FILE_PATH = "#{BASE_DIR}/../../certs/v2_key".freeze

production_db = YAML.load_file(DATABASE_YML_FILE_PATH)["production"]

db_user = production_db["username"]
db_password_encrypt = production_db["password"]
db_password = MiqPassword.try_decrypt(db_password_encrypt)
db_host = production_db["host"]

# system "#{BASE_DIR}/../pg_inspector.rb -h"
ENV['PGPASSWORD'] = db_password
system("#{BASE_DIR}/../pg_inspector.rb servers -u #{db_user} -s #{db_host}")

0 comments on commit ef211a1

Please sign in to comment.