晋太元中,武陵人捕鱼为业。缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷。渔人甚异之,复前行,欲穷其林。 林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田、美池、桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。 见渔人,乃大惊,问所从来。具答之。便要还家,设酒杀鸡作食。村中闻有此人,咸来问讯。自云先世避秦时乱,率妻子邑人来此绝境,不复出焉,遂与外人间隔。问今是何世,乃不知有汉,无论魏晋。此人一一为具言所闻,皆叹惋。余人各复延至其家,皆出酒食。停数日,辞去。此中人语云:“不足为外人道也。”(间隔 一作:隔绝) 既出,得其船,便扶向路,处处志之。及郡下,诣太守,说如此。太守即遣人随其往,寻向所志,遂迷,不复得路。 南阳刘子骥,高尚士也,闻之,欣然规往。未果,寻病终。后遂无问津者。
|
Server : Apache System : Linux srv.rainic.com 4.18.0-553.47.1.el8_10.x86_64 #1 SMP Wed Apr 2 05:45:37 EDT 2025 x86_64 User : rainic ( 1014) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /usr/lib/python3.6/site-packages/sos/report/plugins/ |
Upload File : |
# This file is part of the sos project: https://github.com/sosreport/sos
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# version 2 of the GNU General Public License.
#
# See the LICENSE file in the source distribution for further information.
import os
import yaml
from sos.report.plugins import Plugin, UbuntuPlugin
SNAP_COMMON_PATH = "/var/snap/charmed-postgresql/common"
SNAP_CURRENT_PATH = "/var/snap/charmed-postgresql/current"
PATHS = {
"POSTGRESQL_CONF": SNAP_COMMON_PATH + "/var/lib/postgresql",
"POSTGRESQL_LOGS": SNAP_COMMON_PATH + "/var/log/postgresql",
"PATRONI_CONF": SNAP_CURRENT_PATH + "/etc/patroni",
"PATRONI_LOGS": SNAP_COMMON_PATH + "/var/log/patroni",
"PGBACKREST_CONF": SNAP_CURRENT_PATH + "/etc/pgbackrest",
"PGBACKREST_LOGS": SNAP_COMMON_PATH + "/var/log/pgbackrest",
"PGBOUNCER_CONF": SNAP_CURRENT_PATH + "/etc/pgbouncer",
"PGBOUNCER_LOGS": SNAP_COMMON_PATH + "/var/log/pgbouncer",
}
PATRONI_CONFIG_FILE = f"{PATHS['PATRONI_CONF']}/patroni.yaml"
RUNAS = "snap_daemon"
PSQL = "charmed-postgresql.psql"
PATRONICTL = "charmed-postgresql.patronictl"
class CharmedPostgreSQL(Plugin, UbuntuPlugin):
short_desc = "Charmed PostgreSQL"
plugin_name = "charmed_postgresql"
packages = ('charmed-postgresql',)
@property
def patronictl_args(self) -> str:
return f"--config-file {PATRONI_CONFIG_FILE}"
@property
def psql_args(self) -> str:
return (f"-U {self.postgresql_username} "
f"-h {self.postgresql_host} "
f"-p {self.postgresql_port} "
r"-d postgres -P pager=off")
def setup(self):
# --- FILE EXCLUSIONS ---
# Keys and certificates
self.add_forbidden_path([
f"{PATHS['PATRONI_CONF']}/*.pem",
f"{PATHS['PGBOUNCER_CONF']}/*.pem",
])
# --- FILE INCLUSIONS ---
self.add_copy_spec([
f"{PATHS['POSTGRESQL_CONF']}/*.conf*",
f"{PATHS['POSTGRESQL_LOGS']}",
f"{PATHS['PATRONI_CONF']}/*.y*ml",
f"{PATHS['PATRONI_LOGS']}",
f"{PATHS['PGBACKREST_CONF']}",
f"{PATHS['PGBACKREST_LOGS']}",
f"{PATHS['PGBOUNCER_CONF']}",
f"{PATHS['PGBOUNCER_LOGS']}",
])
# --- SNAP LOGS ---
self.add_journal("snap.charmed-postgresql.*")
# --- SNAP INFO ---
self.add_cmd_output(
"snap info charmed-postgresql",
suggest_filename="snap-info",
)
# Read and parse patroni config, finish setup if there are errors
try:
with open(PATRONI_CONFIG_FILE, encoding='utf-8') as f:
patroni_config = yaml.safe_load(f)
self.patroni_cluster_name = patroni_config["scope"]
postgresql = patroni_config["postgresql"]
host_port = postgresql["connect_address"].split(":")
self.postgresql_host, self.postgresql_port = host_port
authentication = postgresql["authentication"]
superuser = authentication["superuser"]
self.postgresql_username = superuser["username"]
self.postgresql_password = superuser["password"]
except (OSError, yaml.YAMLError, TypeError,
ValueError, KeyError, AttributeError) as error:
self._log_warn("Can not run additional commands due to "
"an error on opening or parsing the config file "
f"{PATRONI_CONFIG_FILE}: "
f'{error}')
return
# --- TOPOLOGY ---
self.add_cmd_output(
(f"{PATRONICTL} {self.patronictl_args} "
f"topology {self.patroni_cluster_name}"),
suggest_filename="patroni-topology",
runas=RUNAS,
)
# --- HISTORY ---
self.add_cmd_output(
(f"{PATRONICTL} {self.patronictl_args} "
f"history {self.patroni_cluster_name}"),
suggest_filename="patroni-history",
runas=RUNAS,
)
# --- DCS CONFIGS ---
self.add_cmd_output(
(f"{PATRONICTL} {self.patronictl_args} "
f"show-config {self.patroni_cluster_name}"),
suggest_filename="patroni-dcs-config",
runas=RUNAS,
)
# ADD DB PASSWORD TO ENVIRONMENT
os.environ["PGPASSWORD"] = self.postgresql_password
# --- DATABASES ---
self.add_cmd_output(
(f"{PSQL} {self.psql_args} "
r"-c '\l+'"),
suggest_filename="postgresql-databases",
runas=RUNAS,
)
# --- USERS ---
self.add_cmd_output(
(f"{PSQL} {self.psql_args} "
r"-c '\duS+'"),
suggest_filename="postgresql-users",
runas=RUNAS,
)
# --- TABLES ---
self.add_cmd_output(
(f"{PSQL} {self.psql_args} "
r"-c '\dtS+'"),
suggest_filename="postgresql-tables",
runas=RUNAS,
)
def postproc(self):
# REMOVE DB PASSWORD FROM ENVIRONMENT
if "PGPASSWORD" in os.environ:
del os.environ["PGPASSWORD"]
# --- SCRUB PASSWORDS ---
# Match lines containing password: and
# followed by anything which may be enclosed with "
self.do_path_regex_sub(
f"{PATHS['PATRONI_CONF']}/*",
r'(password: )"?.*"?',
r'\1"*********"',
)
# https://pgbackrest.org/configuration.html#section-repository/option-repo-s3-key
# https://pgbackrest.org/configuration.html#section-repository/option-repo-s3-key-secret
self.do_path_regex_sub(
f"{PATHS['PGBACKREST_CONF']}/pgbackrest.conf",
r'(.*s3-key.*=).*',
r'\1*********',
)
# https://www.pgbouncer.org/config.html#authentication-file-format
self.do_path_regex_sub(
f"{PATHS['PGBOUNCER_CONF']}/pgbouncer/userlist.txt",
r'(".*" )".*"',
r'\1"*********"',
)