import argparse
import os
import re
import subprocess
import sys
import time
from datetime import datetime
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
if CUR_DIR not in sys.path:
sys.path.insert(0, CUR_DIR)
from config import get_config
def exec_popen(cmd, timeout=600):
"""Execute shell command using subprocess.Popen"""
proc = subprocess.Popen(
["bash", "-c", cmd],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
try:
stdout_b, stderr_b = proc.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
proc.kill()
proc.communicate()
return -1, "", f"Timeout after {timeout}s"
return (
proc.returncode,
stdout_b.decode(errors="replace").strip(),
stderr_b.decode(errors="replace").strip(),
)
def run_shell_as_user(cmd, user, timeout=600):
"""Run shell command as specified user"""
full_cmd = f'su -s /bin/bash - {user} -c "{cmd}"'
return exec_popen(full_cmd, timeout=timeout)
def load_report_cnf(cnf_path):
config = {}
if not os.path.exists(cnf_path):
return config
with open(cnf_path, encoding="utf-8") as f:
content = f.read()
patterns = {
"system_user_name": r'system_user_name="(.*?)"',
"ogsql_user_name": r'ogsql_user_name="(.*?)"',
"ogsql_user_passwd": r'ogsql_user_passwd="(.*?)"',
"ogsql_server_ip": r'ogsql_server_ip="(.*?)"',
"ogsql_server_port": r'ogsql_server_port="(.*?)"',
"ogsql_snapshot_time": r'ogsql_snapshot_time=(\d+)',
"report_output_dir": r'report_output_dir="(.*?)"',
}
for key, pattern in patterns.items():
m = re.search(pattern, content)
if m:
if key == "ogsql_snapshot_time":
config[key] = int(m.group(1))
else:
config[key] = m.group(1)
return config
def resolve_runtime_report_cnf(cfg, report_cnf, args):
resolved = dict(report_cnf)
resolved_port = args.ogsql_server_port or cfg.get_deploy_param(
"ograc_port", report_cnf.get("ogsql_server_port", "1611")
)
resolved["ogsql_server_port"] = str(resolved_port)
resolved_output_dir = args.report_output_dir or report_cnf.get("report_output_dir", "")
if not resolved_output_dir:
resolved_output_dir = cfg.paths.report_output_dir
resolved["report_output_dir"] = resolved_output_dir
resolved_system_user = args.system_user_name or report_cnf.get("system_user_name", "")
if not resolved_system_user:
resolved_system_user = cfg.user
resolved["system_user_name"] = resolved_system_user
return resolved
def ensure_dir(path, mode=0o770, owner=""):
if not os.path.exists(path):
os.makedirs(path, mode=mode)
else:
os.chmod(path, mode)
if owner:
rc, _, err = exec_popen(f"chown -h {owner} {path}")
if rc != 0:
print(f"Warning: Failed to chown {path}: {err}", file=sys.stderr)
def gen_wsr_report(cfg, report_cnf):
ograc_user = cfg.user
ogsql_user_name = report_cnf.get("ogsql_user_name", "sys")
ogsql_user_passwd = report_cnf.get("ogsql_user_passwd", "")
ogsql_server_ip = report_cnf.get("ogsql_server_ip", "127.0.0.1")
ogsql_server_port = report_cnf.get("ogsql_server_port", "1611")
ogsql_snapshot_time = report_cnf.get("ogsql_snapshot_time", 60)
report_output_dir = report_cnf.get("report_output_dir", cfg.paths.report_output_dir)
host_name = os.uname().nodename if hasattr(os, 'uname') else os.environ.get("HOSTNAME", "localhost")
date_time = datetime.now().strftime("%Y%m%d%H%M%S")
if ogsql_user_passwd:
conn_str = f"{ogsql_user_name}/{ogsql_user_passwd}@{ogsql_server_ip}:{ogsql_server_port}"
else:
conn_str = f"{ogsql_user_name}@{ogsql_server_ip}:{ogsql_server_port}"
wsr_list_cmd = f"ogsql {conn_str} -q -c 'wsr list'"
rc, wsr_list_out, err = run_shell_as_user(wsr_list_cmd, ograc_user)
if rc != 0:
print(f"Error: Failed to list WSR snapshots: {err}", file=sys.stderr)
return False
kmc_log = "KmcCheckKmcCtx" in wsr_list_out
snapshot_cmd = f"ogsql {conn_str} -q -c 'CALL WSR$CREATE_SNAPSHOT'"
rc, _, err = run_shell_as_user(snapshot_cmd, ograc_user)
if rc != 0:
print(f"Error: Failed to create first snapshot: {err}", file=sys.stderr)
return False
time.sleep(ogsql_snapshot_time)
rc, _, err = run_shell_as_user(snapshot_cmd, ograc_user)
if rc != 0:
print(f"Error: Failed to create second snapshot: {err}", file=sys.stderr)
return False
rc, wsr_list_out, err = run_shell_as_user(wsr_list_cmd, ograc_user)
if rc != 0:
print(f"Error: Failed to list WSR snapshots after creation: {err}", file=sys.stderr)
return False
lines = wsr_list_out.split('\n')
if kmc_log:
if len(lines) >= 12:
line_12 = lines[11].strip() if len(lines) > 11 else ""
line_11 = lines[10].strip() if len(lines) > 10 else ""
snap_id_1 = line_12.split()[0] if line_12 and len(line_12.split()) > 0 else None
snap_id_2 = line_11.split()[0] if line_11 and len(line_11.split()) > 0 else None
else:
print(f"Error: Not enough lines in wsr list output (expected >=12, got {len(lines)})", file=sys.stderr)
return False
else:
if len(lines) >= 11:
line_11 = lines[10].strip() if len(lines) > 10 else ""
line_10 = lines[9].strip() if len(lines) > 9 else ""
snap_id_1 = line_11.split()[0] if line_11 and len(line_11.split()) > 0 else None
snap_id_2 = line_10.split()[0] if line_10 and len(line_10.split()) > 0 else None
else:
print(f"Error: Not enough lines in wsr list output (expected >=11, got {len(lines)})", file=sys.stderr)
return False
if not snap_id_1 or not snap_id_2:
print("Error: Failed to extract snapshot IDs", file=sys.stderr)
return False
report_file = os.path.join(report_output_dir, f"ograc_wsr_{host_name}_{date_time}.html")
report_cmd = f'ogsql {conn_str} -q -c \'wsr {snap_id_1} {snap_id_2} "{report_file}"\''
rc, _, err = run_shell_as_user(report_cmd, ograc_user)
if rc != 0:
print(f"Error: Failed to generate WSR report: {err}", file=sys.stderr)
return False
print(f"WSR report generated successfully: {report_file}")
return True
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--config", default=os.path.join(CUR_DIR, "report.cnf"))
parser.add_argument("--ogsql-server-port", dest="ogsql_server_port", default="")
parser.add_argument("--report-output-dir", dest="report_output_dir", default="")
parser.add_argument("--system-user-name", dest="system_user_name", default="")
return parser.parse_args()
def main():
args = parse_args()
cfg = get_config()
report_cnf = resolve_runtime_report_cnf(cfg, load_report_cnf(args.config), args)
report_output_dir = report_cnf["report_output_dir"]
system_user_name = report_cnf["system_user_name"]
ograc_common_group = cfg.common_group
ensure_dir(report_output_dir, mode=0o770, owner=f"{system_user_name}:{ograc_common_group}")
if not gen_wsr_report(cfg, report_cnf):
print("Error: Failed to generate WSR report", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()