cmdbox 0.5.1.2__py3-none-any.whl → 0.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cmdbox might be problematic. Click here for more details.
- cmdbox/app/app.py +4 -2
- cmdbox/app/auth/signin.py +633 -631
- cmdbox/app/client.py +10 -10
- cmdbox/app/common.py +50 -6
- cmdbox/app/commons/convert.py +9 -0
- cmdbox/app/commons/module.py +113 -113
- cmdbox/app/commons/redis_client.py +40 -29
- cmdbox/app/edge.py +4 -4
- cmdbox/app/features/cli/audit_base.py +135 -0
- cmdbox/app/features/cli/cmdbox_audit_createdb.py +224 -0
- cmdbox/app/features/cli/cmdbox_audit_delete.py +299 -0
- cmdbox/app/features/cli/cmdbox_audit_search.py +350 -0
- cmdbox/app/features/cli/cmdbox_audit_write.py +240 -0
- cmdbox/app/features/cli/cmdbox_client_file_copy.py +207 -207
- cmdbox/app/features/cli/cmdbox_client_file_download.py +207 -207
- cmdbox/app/features/cli/cmdbox_client_file_list.py +193 -193
- cmdbox/app/features/cli/cmdbox_client_file_mkdir.py +191 -191
- cmdbox/app/features/cli/cmdbox_client_file_move.py +199 -199
- cmdbox/app/features/cli/cmdbox_client_file_remove.py +190 -190
- cmdbox/app/features/cli/cmdbox_client_file_rmdir.py +190 -190
- cmdbox/app/features/cli/cmdbox_client_file_upload.py +212 -212
- cmdbox/app/features/cli/cmdbox_client_server_info.py +166 -166
- cmdbox/app/features/cli/cmdbox_server_list.py +88 -88
- cmdbox/app/features/cli/cmdbox_server_stop.py +138 -138
- cmdbox/app/features/web/cmdbox_web_del_cmd.py +2 -0
- cmdbox/app/features/web/cmdbox_web_del_pipe.py +1 -0
- cmdbox/app/features/web/cmdbox_web_do_signin.py +12 -2
- cmdbox/app/features/web/cmdbox_web_do_signout.py +1 -0
- cmdbox/app/features/web/cmdbox_web_exec_cmd.py +25 -1
- cmdbox/app/features/web/cmdbox_web_exec_pipe.py +1 -0
- cmdbox/app/features/web/cmdbox_web_filer download.py +43 -42
- cmdbox/app/features/web/cmdbox_web_filer.py +1 -0
- cmdbox/app/features/web/cmdbox_web_filer_upload.py +65 -64
- cmdbox/app/features/web/cmdbox_web_gui.py +166 -165
- cmdbox/app/features/web/cmdbox_web_load_pin.py +43 -43
- cmdbox/app/features/web/cmdbox_web_raw_pipe.py +87 -87
- cmdbox/app/features/web/cmdbox_web_save_cmd.py +1 -0
- cmdbox/app/features/web/cmdbox_web_save_pin.py +42 -42
- cmdbox/app/features/web/cmdbox_web_save_pipe.py +1 -0
- cmdbox/app/features/web/cmdbox_web_users.py +12 -0
- cmdbox/app/options.py +767 -601
- cmdbox/extensions/features.yml +20 -0
- cmdbox/extensions/sample_project/sample/app/features/cli/sample_client_time.py +82 -82
- cmdbox/extensions/sample_project/sample/app/features/cli/sample_server_time.py +145 -145
- cmdbox/licenses/{LICENSE.Sphinx.8.1.3(BSD License).txt → LICENSE.Sphinx.8.2.3(UNKNOWN).txt} +1 -1
- cmdbox/licenses/{LICENSE.babel.2.16.0(BSD License).txt → LICENSE.babel.2.17.0(BSD License).txt } +1 -1
- cmdbox/licenses/{LICENSE.pkginfo.1.10.0(MIT License).txt → LICENSE.charset-normalizer.3.4.1(MIT License).txt } +1 -1
- cmdbox/licenses/LICENSE.gunicorn.23.0.0(MIT License).txt +23 -0
- cmdbox/licenses/LICENSE.importlib_metadata.8.6.1(Apache Software License).txt +202 -0
- cmdbox/licenses/LICENSE.nh3.0.2.21(MIT).txt +21 -0
- cmdbox/licenses/{LICENSE.pillow.11.0.0(CMU License (MIT-CMU)).txt → LICENSE.pillow.11.1.0(CMU License (MIT-CMU)).txt } +27 -40
- cmdbox/licenses/LICENSE.plyer.2.1.0(MIT License).txt +19 -0
- cmdbox/licenses/LICENSE.prompt_toolkit.3.0.50(BSD License).txt +27 -0
- cmdbox/licenses/LICENSE.psycopg-binary.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt +165 -0
- cmdbox/licenses/LICENSE.psycopg-pool.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt +165 -0
- cmdbox/licenses/LICENSE.psycopg.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt +165 -0
- cmdbox/licenses/LICENSE.pycryptodome.3.22.0(BSD License; Public Domain).txt +61 -0
- cmdbox/licenses/LICENSE.pystray.0.19.5(GNU Lesser General Public License v3 (LGPLv3)).txt +674 -0
- cmdbox/licenses/LICENSE.questionary.2.1.0(MIT License).txt +19 -0
- cmdbox/licenses/LICENSE.roman-numerals-py.3.1.0(CC0 1.0 Universal (CC0 1.0) Public Domain Dedication; Zero-Clause BSD (0BSD)).txt +146 -0
- cmdbox/licenses/{LICENSE.six.1.16.0(MIT License).txt → LICENSE.six.1.17.0(MIT License).txt } +1 -1
- cmdbox/licenses/{LICENSE.charset-normalizer.3.4.0(MIT License).txt → LICENSE.typing-inspection.0.4.0(MIT License).txt } +2 -2
- cmdbox/licenses/LICENSE.tzdata.2025.2(Apache Software License).txt +15 -0
- cmdbox/licenses/files.txt +48 -36
- cmdbox/logconf_audit.yml +30 -0
- cmdbox/logconf_cmdbox.yml +30 -0
- cmdbox/version.py +2 -2
- cmdbox/web/assets/cmdbox/color_mode.css +516 -0
- cmdbox/web/assets/cmdbox/common.js +19 -0
- cmdbox/web/assets/cmdbox/list_cmd.js +9 -10
- cmdbox/web/assets/cmdbox/main.js +2 -2
- cmdbox/web/assets/cmdbox/result.js +2 -2
- cmdbox/web/assets/cmdbox/signin.js +2 -2
- cmdbox/web/assets/cmdbox/users.js +2 -3
- cmdbox/web/assets/cmdbox/view_result.js +1 -1
- cmdbox/web/assets/filer/main.js +2 -2
- cmdbox/web/filer.html +16 -2
- cmdbox/web/gui.html +15 -1
- cmdbox/web/result.html +15 -1
- cmdbox/web/signin.html +35 -14
- cmdbox/web/users.html +15 -1
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/METADATA +25 -5
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/RECORD +116 -96
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/entry_points.txt +0 -1
- cmdbox/licenses/LICENSE.nh3.0.2.18(MIT).txt +0 -1
- /cmdbox/licenses/{LICENSE.Jinja2.3.1.4(BSD License).txt → LICENSE.Jinja2.3.1.6(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.Pygments.2.18.0(BSD License).txt → LICENSE.Pygments.2.19.1(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.anyio.4.6.2.post1(MIT License).txt → LICENSE.anyio.4.9.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.argcomplete.3.5.1(Apache Software License).txt → LICENSE.argcomplete.3.6.1(Apache Software License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.certifi.2024.8.30(Mozilla Public License 2.0 (MPL 2.0)).txt → LICENSE.certifi.2025.1.31(Mozilla Public License 2.0 (MPL 2.0)).txt} +0 -0
- /cmdbox/licenses/{LICENSE.click.8.1.7(BSD License).txt → LICENSE.click.8.1.8(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.cryptography.43.0.3(Apache Software License; BSD License).txt → LICENSE.cryptography.44.0.2(Apache Software License; BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.fastapi.0.115.5(MIT License).txt → LICENSE.fastapi.0.115.12(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.importlib_metadata.8.5.0(Apache Software License).txt → LICENSE.id.1.5.0(Apache Software License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.keyring.25.5.0(MIT License).txt → LICENSE.keyring.25.6.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.more-itertools.10.5.0(MIT License).txt → LICENSE.more-itertools.10.6.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.numpy.2.1.3(BSD License).txt → LICENSE.numpy.2.2.4(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.prettytable.3.12.0(BSD License).txt → LICENSE.prettytable.3.16.0(UNKNOWN).txt} +0 -0
- /cmdbox/licenses/{LICENSE.pydantic.2.10.2(MIT License).txt → LICENSE.pydantic.2.11.1(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.pydantic_core.2.27.1(MIT License).txt → LICENSE.pydantic_core.2.33.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.python-dotenv.1.0.1(BSD License).txt → LICENSE.python-dotenv.1.1.0(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.python-multipart.0.0.17(Apache Software License).txt → LICENSE.python-multipart.0.0.20(Apache Software License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.redis.5.2.0(MIT License).txt → LICENSE.redis.5.2.1(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.rich.13.9.4(MIT License).txt → LICENSE.rich.14.0.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.sphinx-intl.2.3.0(BSD License).txt → LICENSE.sphinx-intl.2.3.1(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.starlette.0.41.3(BSD License).txt → LICENSE.starlette.0.46.1(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.tomli.2.1.0(MIT License).txt → LICENSE.tomli.2.2.1(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.twine.5.1.1(Apache Software License).txt → LICENSE.twine.6.1.0(Apache Software License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.typing_extensions.4.12.2(Python Software Foundation License).txt → LICENSE.typing_extensions.4.13.0(UNKNOWN).txt} +0 -0
- /cmdbox/licenses/{LICENSE.urllib3.2.2.3(MIT License).txt → LICENSE.urllib3.2.3.0(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.uvicorn.0.32.1(BSD License).txt → LICENSE.uvicorn.0.34.0(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.watchfiles.1.0.0(MIT License).txt → LICENSE.watchfiles.1.0.4(MIT License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.websockets.14.1(BSD License).txt → LICENSE.websockets.15.0.1(BSD License).txt} +0 -0
- /cmdbox/licenses/{LICENSE.zope.interface.7.1.1(Zope Public License).txt → LICENSE.zope.interface.7.2(Zope Public License).txt} +0 -0
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/LICENSE +0 -0
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/WHEEL +0 -0
- {cmdbox-0.5.1.2.dist-info → cmdbox-0.5.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from cmdbox.app import feature
|
|
2
|
+
from cmdbox.app.options import Options
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
import logging
|
|
6
|
+
import psycopg
|
|
7
|
+
import sqlite3
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AuditBase(feature.ResultEdgeFeature):
|
|
11
|
+
|
|
12
|
+
def get_option(self):
|
|
13
|
+
"""
|
|
14
|
+
この機能のオプションを返します
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Dict[str, Any]: オプション
|
|
18
|
+
"""
|
|
19
|
+
return dict(
|
|
20
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
21
|
+
discription_ja="",
|
|
22
|
+
discription_en="",
|
|
23
|
+
choice=[
|
|
24
|
+
dict(opt="host", type=Options.T_STR, default=self.default_host, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
25
|
+
discription_ja="Redisサーバーのサービスホストを指定します。",
|
|
26
|
+
discription_en="Specify the service host of the Redis server."),
|
|
27
|
+
dict(opt="port", type=Options.T_INT, default=self.default_port, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
28
|
+
discription_ja="Redisサーバーのサービスポートを指定します。",
|
|
29
|
+
discription_en="Specify the service port of the Redis server."),
|
|
30
|
+
dict(opt="password", type=Options.T_STR, default=self.default_pass, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
31
|
+
discription_ja=f"Redisサーバーのアクセスパスワード(任意)を指定します。省略時は `{self.default_pass}` を使用します。",
|
|
32
|
+
discription_en=f"Specify the access password of the Redis server (optional). If omitted, `{self.default_pass}` is used."),
|
|
33
|
+
dict(opt="svname", type=Options.T_STR, default="server", required=True, multi=False, hide=True, choice=None, web="readonly",
|
|
34
|
+
discription_ja="サーバーのサービス名を指定します。省略時は `server` を使用します。",
|
|
35
|
+
discription_en="Specify the service name of the inference server. If omitted, `server` is used."),
|
|
36
|
+
|
|
37
|
+
dict(opt="retry_count", type=Options.T_INT, default=3, required=False, multi=False, hide=True, choice=None,
|
|
38
|
+
discription_ja="Redisサーバーへの再接続回数を指定します。0以下を指定すると永遠に再接続を行います。",
|
|
39
|
+
discription_en="Specifies the number of reconnections to the Redis server.If less than 0 is specified, reconnection is forever."),
|
|
40
|
+
dict(opt="retry_interval", type=Options.T_INT, default=5, required=False, multi=False, hide=True, choice=None,
|
|
41
|
+
discription_ja="Redisサーバーに再接続までの秒数を指定します。",
|
|
42
|
+
discription_en="Specifies the number of seconds before reconnecting to the Redis server."),
|
|
43
|
+
dict(opt="timeout", type=Options.T_INT, default="15", required=False, multi=False, hide=True, choice=None,
|
|
44
|
+
discription_ja="サーバーの応答が返ってくるまでの最大待ち時間を指定。",
|
|
45
|
+
discription_en="Specify the maximum waiting time until the server responds."),
|
|
46
|
+
|
|
47
|
+
dict(opt="pg_enabled", type=Options.T_BOOL, default=False, required=False, multi=False, hide=True, choice=[True, False], web="mask",
|
|
48
|
+
discription_ja="postgresqlデータベース・サーバを使用する場合はTrueを指定します。",
|
|
49
|
+
discription_en="Specify True if using the postgresql database server."),
|
|
50
|
+
dict(opt="pg_host", type=Options.T_STR, default='localhost', required=False, multi=False, hide=True, choice=None, web="mask",
|
|
51
|
+
discription_ja="postgresqlホストを指定する。",
|
|
52
|
+
discription_en="Specify the postgresql host."),
|
|
53
|
+
dict(opt="pg_port", type=Options.T_INT, default=5432, required=False, multi=False, hide=True, choice=None, web="mask",
|
|
54
|
+
discription_ja="postgresqlのポートを指定する。",
|
|
55
|
+
discription_en="Specify the postgresql port."),
|
|
56
|
+
dict(opt="pg_user", type=Options.T_STR, default='postgres', required=False, multi=False, hide=True, choice=None, web="mask",
|
|
57
|
+
discription_ja="postgresqlのユーザー名を指定する。",
|
|
58
|
+
discription_en="Specify the postgresql user name."),
|
|
59
|
+
dict(opt="pg_password", type=Options.T_STR, default='postgres', required=False, multi=False, hide=True, choice=None, web="mask",
|
|
60
|
+
discription_ja="postgresqlのパスワードを指定する。",
|
|
61
|
+
discription_en="Specify the postgresql password."),
|
|
62
|
+
dict(opt="pg_dbname", type=Options.T_STR, default='audit', required=False, multi=False, hide=True, choice=None,
|
|
63
|
+
discription_ja="postgresqlデータベース名を指定します。",
|
|
64
|
+
discription_en="Specify the postgresql database name."),
|
|
65
|
+
]
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def initdb(self, data_dir:Path, logger:logging.Logger, pg_enabled:bool, pg_host:str, pg_port:int, pg_user:str, pg_password:str, pg_dbname:str) -> Any:
|
|
69
|
+
"""
|
|
70
|
+
データベースを初期化します
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
data_dir (Path): データディレクトリ
|
|
74
|
+
logger (logging.Logger): ロガー
|
|
75
|
+
pg_enabled (bool): PostgreSQLを使用するかどうか
|
|
76
|
+
pg_host (str): PostgreSQLホスト
|
|
77
|
+
pg_port (int): PostgreSQLポート
|
|
78
|
+
pg_user (str): PostgreSQLユーザー名
|
|
79
|
+
pg_password (str): PostgreSQLパスワード
|
|
80
|
+
pg_dbname (str): PostgreSQLデータベース名
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Any: データベース接続オブジェクト
|
|
84
|
+
"""
|
|
85
|
+
if pg_enabled:
|
|
86
|
+
constr = f"host={pg_host} port={pg_port} user={pg_user} password={pg_password} dbname={pg_dbname} connect_timeout=60"
|
|
87
|
+
conn = psycopg.connect(constr, autocommit=False)
|
|
88
|
+
cursor = conn.cursor()
|
|
89
|
+
try:
|
|
90
|
+
cursor.execute("SELECT count(*) FROM information_schema.tables WHERE table_name='audit'")
|
|
91
|
+
if cursor.fetchone()[0] == 0:
|
|
92
|
+
# テーブルが存在しない場合は作成
|
|
93
|
+
cursor.execute('''
|
|
94
|
+
CREATE TABLE IF NOT EXISTS audit (
|
|
95
|
+
id SERIAL PRIMARY KEY,
|
|
96
|
+
audit_type TEXT,
|
|
97
|
+
clmsg_id TEXT,
|
|
98
|
+
clmsg_date TIMESTAMP WITH TIME ZONE,
|
|
99
|
+
clmsg_src TEXT,
|
|
100
|
+
clmsg_user TEXT,
|
|
101
|
+
clmsg_body JSON,
|
|
102
|
+
clmsg_tag JSON,
|
|
103
|
+
svmsg_id TEXT,
|
|
104
|
+
svmsg_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
105
|
+
)
|
|
106
|
+
''')
|
|
107
|
+
finally:
|
|
108
|
+
cursor.close()
|
|
109
|
+
conn.rollback()
|
|
110
|
+
else:
|
|
111
|
+
db_path = data_dir / '.audit' / 'audit.db'
|
|
112
|
+
db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
113
|
+
conn = sqlite3.connect(db_path)
|
|
114
|
+
cursor = conn.cursor()
|
|
115
|
+
try:
|
|
116
|
+
cursor.execute('SELECT COUNT(*) FROM sqlite_master WHERE TYPE="table" AND NAME="audit"')
|
|
117
|
+
if cursor.fetchone()[0] == 0:
|
|
118
|
+
# テーブルが存在しない場合は作成
|
|
119
|
+
cursor.execute('''
|
|
120
|
+
CREATE TABLE IF NOT EXISTS audit (
|
|
121
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
122
|
+
audit_type TEXT,
|
|
123
|
+
clmsg_id TEXT,
|
|
124
|
+
clmsg_date TEXT,
|
|
125
|
+
clmsg_src TEXT,
|
|
126
|
+
clmsg_user TEXT,
|
|
127
|
+
clmsg_body JSON,
|
|
128
|
+
clmsg_tag JSON,
|
|
129
|
+
svmsg_id TEXT,
|
|
130
|
+
svmsg_date TEXT DEFAULT CURRENT_TIMESTAMP
|
|
131
|
+
)
|
|
132
|
+
''')
|
|
133
|
+
finally:
|
|
134
|
+
cursor.close()
|
|
135
|
+
return conn
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
from cmdbox.app import common, client, feature
|
|
2
|
+
from cmdbox.app.commons import convert, redis_client
|
|
3
|
+
from cmdbox.app.features.cli import audit_base
|
|
4
|
+
from cmdbox.app.options import Options
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Dict, Any, Tuple, List, Union
|
|
8
|
+
import argparse
|
|
9
|
+
import logging
|
|
10
|
+
import json
|
|
11
|
+
import psycopg
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AuditCreatedb(feature.UnsupportEdgeFeature):
|
|
15
|
+
def get_mode(self) -> Union[str, List[str]]:
|
|
16
|
+
"""
|
|
17
|
+
この機能のモードを返します
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Union[str, List[str]]: モード
|
|
21
|
+
"""
|
|
22
|
+
return 'audit'
|
|
23
|
+
|
|
24
|
+
def get_cmd(self):
|
|
25
|
+
"""
|
|
26
|
+
この機能のコマンドを返します
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
str: コマンド
|
|
30
|
+
"""
|
|
31
|
+
return 'createdb'
|
|
32
|
+
|
|
33
|
+
def get_option(self):
|
|
34
|
+
"""
|
|
35
|
+
この機能のオプションを返します
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Dict[str, Any]: オプション
|
|
39
|
+
"""
|
|
40
|
+
return dict(
|
|
41
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=True,
|
|
42
|
+
discription_ja="監査を記録するデータベースを作成します。",
|
|
43
|
+
discription_en="Create a database to record audits.",
|
|
44
|
+
choice=[
|
|
45
|
+
dict(opt="pg_host", type=Options.T_STR, default='localhost', required=True, multi=False, hide=False, choice=None,
|
|
46
|
+
discription_ja="postgresqlホストを指定する。",
|
|
47
|
+
discription_en="Specify the postgresql host."),
|
|
48
|
+
dict(opt="pg_port", type=Options.T_INT, default=5432, required=True, multi=False, hide=False, choice=None,
|
|
49
|
+
discription_ja="postgresqlのポートを指定する。",
|
|
50
|
+
discription_en="Specify the postgresql port."),
|
|
51
|
+
dict(opt="pg_user", type=Options.T_STR, default='postgres', required=True, multi=False, hide=False, choice=None,
|
|
52
|
+
discription_ja="postgresqlのユーザー名を指定する。",
|
|
53
|
+
discription_en="Specify the postgresql user name."),
|
|
54
|
+
dict(opt="pg_password", type=Options.T_STR, default='postgres', required=True, multi=False, hide=False, choice=None,
|
|
55
|
+
discription_ja="postgresqlのパスワードを指定する。",
|
|
56
|
+
discription_en="Specify the postgresql password."),
|
|
57
|
+
dict(opt="pg_dbname", type=Options.T_STR, default='audit', required=True, multi=False, hide=False, choice=None,
|
|
58
|
+
discription_ja="postgresqlデータベース名を指定します。",
|
|
59
|
+
discription_en="Specify the postgresql database name."),
|
|
60
|
+
dict(opt="new_pg_dbname", type=Options.T_STR, default='audit', required=True, multi=False, hide=False, choice=None,
|
|
61
|
+
discription_ja="新しいpostgresqlデータベース名を指定します。",
|
|
62
|
+
discription_en="Specify a new postgresql database name."),
|
|
63
|
+
|
|
64
|
+
dict(opt="host", type=Options.T_STR, default=self.default_host, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
65
|
+
discription_ja="Redisサーバーのサービスホストを指定します。",
|
|
66
|
+
discription_en="Specify the service host of the Redis server."),
|
|
67
|
+
dict(opt="port", type=Options.T_INT, default=self.default_port, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
68
|
+
discription_ja="Redisサーバーのサービスポートを指定します。",
|
|
69
|
+
discription_en="Specify the service port of the Redis server."),
|
|
70
|
+
dict(opt="password", type=Options.T_STR, default=self.default_pass, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
71
|
+
discription_ja=f"Redisサーバーのアクセスパスワード(任意)を指定します。省略時は `{self.default_pass}` を使用します。",
|
|
72
|
+
discription_en=f"Specify the access password of the Redis server (optional). If omitted, `{self.default_pass}` is used."),
|
|
73
|
+
dict(opt="svname", type=Options.T_STR, default="server", required=True, multi=False, hide=True, choice=None, web="readonly",
|
|
74
|
+
discription_ja="サーバーのサービス名を指定します。省略時は `server` を使用します。",
|
|
75
|
+
discription_en="Specify the service name of the inference server. If omitted, `server` is used."),
|
|
76
|
+
dict(opt="retry_count", type=Options.T_INT, default=3, required=False, multi=False, hide=True, choice=None,
|
|
77
|
+
discription_ja="Redisサーバーへの再接続回数を指定します。0以下を指定すると永遠に再接続を行います。",
|
|
78
|
+
discription_en="Specifies the number of reconnections to the Redis server.If less than 0 is specified, reconnection is forever."),
|
|
79
|
+
dict(opt="retry_interval", type=Options.T_INT, default=5, required=False, multi=False, hide=True, choice=None,
|
|
80
|
+
discription_ja="Redisサーバーに再接続までの秒数を指定します。",
|
|
81
|
+
discription_en="Specifies the number of seconds before reconnecting to the Redis server."),
|
|
82
|
+
dict(opt="timeout", type=Options.T_INT, default="15", required=False, multi=False, hide=True, choice=None,
|
|
83
|
+
discription_ja="サーバーの応答が返ってくるまでの最大待ち時間を指定。",
|
|
84
|
+
discription_en="Specify the maximum waiting time until the server responds."),
|
|
85
|
+
]
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_svcmd(self):
|
|
90
|
+
"""
|
|
91
|
+
この機能のサーバー側のコマンドを返します
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
str: サーバー側のコマンド
|
|
95
|
+
"""
|
|
96
|
+
return 'audit_create'
|
|
97
|
+
|
|
98
|
+
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
|
|
99
|
+
"""
|
|
100
|
+
この機能の実行を行います
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
logger (logging.Logger): ロガー
|
|
104
|
+
args (argparse.Namespace): 引数
|
|
105
|
+
tm (float): 実行開始時間
|
|
106
|
+
pf (List[Dict[str, float]]): 呼出元のパフォーマンス情報
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
Tuple[int, Dict[str, Any], Any]: 終了コード, 結果, オブジェクト
|
|
110
|
+
"""
|
|
111
|
+
if args.svname is None:
|
|
112
|
+
msg = dict(warn=f"Please specify the --svname option.")
|
|
113
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
114
|
+
return 1, msg, None
|
|
115
|
+
if args.pg_host is None:
|
|
116
|
+
msg = dict(warn=f"Please specify the --pg_host option.")
|
|
117
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
118
|
+
return 1, msg, None
|
|
119
|
+
if args.pg_port is None:
|
|
120
|
+
msg = dict(warn=f"Please specify the --pg_port option.")
|
|
121
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
122
|
+
return 1, msg, None
|
|
123
|
+
if args.pg_user is None:
|
|
124
|
+
msg = dict(warn=f"Please specify the --pg_user option.")
|
|
125
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
126
|
+
return 1, msg, None
|
|
127
|
+
if args.pg_password is None:
|
|
128
|
+
msg = dict(warn=f"Please specify the --pg_password option.")
|
|
129
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
130
|
+
return 1, msg, None
|
|
131
|
+
if args.pg_dbname is None:
|
|
132
|
+
msg = dict(warn=f"Please specify the --pg_dbname option.")
|
|
133
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
134
|
+
return 1, msg, None
|
|
135
|
+
if args.new_pg_dbname is None:
|
|
136
|
+
msg = dict(warn=f"Please specify the --new_pg_dbname option.")
|
|
137
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
138
|
+
return 1, msg, None
|
|
139
|
+
|
|
140
|
+
pg_host_b64 = convert.str2b64str(args.pg_host)
|
|
141
|
+
pg_port = args.pg_port if isinstance(args.pg_port, int) else None
|
|
142
|
+
pg_user_b64 = convert.str2b64str(args.pg_user)
|
|
143
|
+
pg_password_b64 = convert.str2b64str(args.pg_password)
|
|
144
|
+
pg_dbname_b64 = convert.str2b64str(args.pg_dbname)
|
|
145
|
+
new_pg_dbname_b64 = convert.str2b64str(args.new_pg_dbname)
|
|
146
|
+
|
|
147
|
+
cl = client.Client(logger, redis_host=args.host, redis_port=args.port, redis_password=args.password, svname=args.svname)
|
|
148
|
+
ret = cl.redis_cli.send_cmd(self.get_svcmd(),
|
|
149
|
+
[pg_host_b64, pg_port, pg_user_b64, pg_password_b64, pg_dbname_b64, new_pg_dbname_b64],
|
|
150
|
+
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout)
|
|
151
|
+
common.print_format(ret, False, tm, None, False, pf=pf)
|
|
152
|
+
if 'success' not in ret:
|
|
153
|
+
return 1, ret, cl
|
|
154
|
+
return 0, ret, cl
|
|
155
|
+
|
|
156
|
+
def is_cluster_redirect(self):
|
|
157
|
+
"""
|
|
158
|
+
クラスター宛のメッセージの場合、メッセージを転送するかどうかを返します
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
bool: メッセージを転送する場合はTrue
|
|
162
|
+
"""
|
|
163
|
+
return False
|
|
164
|
+
|
|
165
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
166
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
167
|
+
"""
|
|
168
|
+
この機能のサーバー側の実行を行います
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
data_dir (Path): データディレクトリ
|
|
172
|
+
logger (logging.Logger): ロガー
|
|
173
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
174
|
+
msg (List[str]): 受信メッセージ
|
|
175
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
int: 終了コード
|
|
179
|
+
"""
|
|
180
|
+
pg_host = convert.b64str2str(msg[2])
|
|
181
|
+
pg_port = int(msg[3]) if msg[3]!='None' else None
|
|
182
|
+
pg_user = convert.b64str2str(msg[4])
|
|
183
|
+
pg_password = convert.b64str2str(msg[5])
|
|
184
|
+
pg_dbname = convert.b64str2str(msg[6])
|
|
185
|
+
new_pg_dbname = convert.b64str2str(msg[7])
|
|
186
|
+
st = self.createdb(msg[1], pg_host, pg_port, pg_user, pg_password, pg_dbname, new_pg_dbname,
|
|
187
|
+
data_dir, logger, redis_cli)
|
|
188
|
+
return st
|
|
189
|
+
|
|
190
|
+
def createdb(self, reskey:str, pg_host:str, pg_port:int, pg_user:str, pg_password:str, pg_dbname:str, new_pg_dbname:str,
|
|
191
|
+
data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient) -> int:
|
|
192
|
+
"""
|
|
193
|
+
監査ログデータベースを作成する
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
reskey (str): レスポンスキー
|
|
197
|
+
pg_host (str): PostgreSQLホスト
|
|
198
|
+
pg_port (int): PostgreSQLポート
|
|
199
|
+
pg_user (str): PostgreSQLユーザー
|
|
200
|
+
pg_password (str): PostgreSQLパスワード
|
|
201
|
+
pg_dbname (str): PostgreSQLデータベース名
|
|
202
|
+
new_pg_dbname (str): 新しいPostgreSQLデータベース名
|
|
203
|
+
data_dir (Path): データディレクトリ
|
|
204
|
+
logger (logging.Logger): ロガー
|
|
205
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
int: レスポンスコード
|
|
209
|
+
"""
|
|
210
|
+
try:
|
|
211
|
+
constr = f"host={pg_host} port={pg_port} user={pg_user} password={pg_password} dbname={pg_dbname} connect_timeout=5"
|
|
212
|
+
with psycopg.connect(constr, autocommit=True) as conn:
|
|
213
|
+
cursor = conn.cursor()
|
|
214
|
+
try:
|
|
215
|
+
cursor.execute(f'create database {new_pg_dbname}')
|
|
216
|
+
rescode, msg = (self.RESP_SCCESS, dict(success=True))
|
|
217
|
+
redis_cli.rpush(reskey, msg)
|
|
218
|
+
return rescode
|
|
219
|
+
finally:
|
|
220
|
+
cursor.close()
|
|
221
|
+
except Exception as e:
|
|
222
|
+
logger.warning(f"Failed to createdb: {e}", exc_info=True)
|
|
223
|
+
redis_cli.rpush(reskey, dict(warn=f"Failed to createdb: {e}"))
|
|
224
|
+
return self.RESP_WARN
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
from cmdbox.app import common, client
|
|
2
|
+
from cmdbox.app.commons import convert, redis_client
|
|
3
|
+
from cmdbox.app.features.cli import audit_base
|
|
4
|
+
from cmdbox.app.options import Options
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from psycopg.rows import dict_row
|
|
7
|
+
from typing import Dict, Any, Tuple, List, Union
|
|
8
|
+
import argparse
|
|
9
|
+
import logging
|
|
10
|
+
import json
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AuditDelete(audit_base.AuditBase):
|
|
15
|
+
def get_mode(self) -> Union[str, List[str]]:
|
|
16
|
+
"""
|
|
17
|
+
この機能のモードを返します
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Union[str, List[str]]: モード
|
|
21
|
+
"""
|
|
22
|
+
return 'audit'
|
|
23
|
+
|
|
24
|
+
def get_cmd(self):
|
|
25
|
+
"""
|
|
26
|
+
この機能のコマンドを返します
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
str: コマンド
|
|
30
|
+
"""
|
|
31
|
+
return 'delete'
|
|
32
|
+
|
|
33
|
+
def get_option(self):
|
|
34
|
+
"""
|
|
35
|
+
この機能のオプションを返します
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Dict[str, Any]: オプション
|
|
39
|
+
"""
|
|
40
|
+
opt = super().get_option()
|
|
41
|
+
opt['discription_ja'] = "監査ログを削除します。"
|
|
42
|
+
opt['discription_en'] = "Delete the audit log."
|
|
43
|
+
opt['choice'] += [
|
|
44
|
+
dict(opt="delete_audit_type", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=Options.AUDITS,
|
|
45
|
+
discription_ja="削除条件の監査の種類を指定します。",
|
|
46
|
+
discription_en="Specifies the type of audit for the delete condition."),
|
|
47
|
+
dict(opt="delete_clmsg_id", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
|
|
48
|
+
discription_ja="削除条件のクライアントのメッセージIDを指定します。",
|
|
49
|
+
discription_en="Specify the message ID of the client for the delete condition."),
|
|
50
|
+
dict(opt="delete_clmsg_sdate", type=Options.T_DATETIME, default=None, required=False, multi=False, hide=False, choice=None,
|
|
51
|
+
discription_ja="削除条件のクライアントのメッセージ発生日時(開始)を指定します。",
|
|
52
|
+
discription_en="Specify the date and time (start) when the message occurred for the client in the delete condition."),
|
|
53
|
+
dict(opt="delete_clmsg_edate", type=Options.T_DATETIME, default=None, required=False, multi=False, hide=False, choice=None,
|
|
54
|
+
discription_ja="削除条件のクライアントのメッセージ発生日時(終了)を指定します。",
|
|
55
|
+
discription_en="Specify the date and time (end) when the message occurred for the client in the delete condition."),
|
|
56
|
+
dict(opt="delete_clmsg_src", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
|
|
57
|
+
discription_ja="削除条件のクライアントのメッセージの発生源を指定します。LIKE検索を行います。",
|
|
58
|
+
discription_en="Specifies the source of the message for the client in the delete condition; performs a LIKE search."),
|
|
59
|
+
dict(opt="delete_clmsg_user", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
|
|
60
|
+
discription_ja="削除条件のクライアントのメッセージの発生させたユーザーを指定します。LIKE検索を行います。",
|
|
61
|
+
discription_en="Specifies the user who generated the message for the client in the delete condition; performs a LIKE search."),
|
|
62
|
+
dict(opt="delete_clmsg_body", type=Options.T_DICT, default=None, required=False, multi=True, hide=False, choice=None,
|
|
63
|
+
discription_ja="削除条件のクライアントのメッセージの本文を辞書形式で指定します。LIKE検索を行います。",
|
|
64
|
+
discription_en="Specifies the body of the client's message in the delete condition in dictionary format; performs a LIKE search."),
|
|
65
|
+
dict(opt="delete_clmsg_tag", type=Options.T_STR, default=None, required=False, multi=True, hide=False, choice=None,
|
|
66
|
+
discription_ja="削除条件のクライアントのメッセージのタグを指定します。",
|
|
67
|
+
discription_en="Specifies the tag of the client's message in the delete condition."),
|
|
68
|
+
dict(opt="delete_svmsg_id", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
|
|
69
|
+
discription_ja="削除条件のサーバーのメッセージIDを指定します。",
|
|
70
|
+
discription_en="Specify the message ID of the server for the delete condition."),
|
|
71
|
+
dict(opt="delete_svmsg_sdate", type=Options.T_DATETIME, default=None, required=False, multi=False, hide=False, choice=None,
|
|
72
|
+
discription_ja="削除条件のサーバーのメッセージ発生日時(開始)を指定します。",
|
|
73
|
+
discription_en="Specify the date and time (start) when the message occurred for the server in the delete condition."),
|
|
74
|
+
dict(opt="delete_svmsg_edate", type=Options.T_DATETIME, default=None, required=False, multi=False, hide=False, choice=None,
|
|
75
|
+
discription_ja="削除条件のサーバーのメッセージ発生日時(終了)を指定します。",
|
|
76
|
+
discription_en="Specify the date and time (end) when the message occurred for the server in the delete condition."),
|
|
77
|
+
]
|
|
78
|
+
return opt
|
|
79
|
+
|
|
80
|
+
def get_svcmd(self):
|
|
81
|
+
"""
|
|
82
|
+
この機能のサーバー側のコマンドを返します
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
str: サーバー側のコマンド
|
|
86
|
+
"""
|
|
87
|
+
return 'audit_delete'
|
|
88
|
+
|
|
89
|
+
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
|
|
90
|
+
"""
|
|
91
|
+
この機能の実行を行います
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
logger (logging.Logger): ロガー
|
|
95
|
+
args (argparse.Namespace): 引数
|
|
96
|
+
tm (float): 実行開始時間
|
|
97
|
+
pf (List[Dict[str, float]]): 呼出元のパフォーマンス情報
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Tuple[int, Dict[str, Any], Any]: 終了コード, 結果, オブジェクト
|
|
101
|
+
"""
|
|
102
|
+
if args.svname is None:
|
|
103
|
+
msg = dict(warn=f"Please specify the --svname option.")
|
|
104
|
+
common.print_format(msg, args.format, tm, None, False, pf=pf)
|
|
105
|
+
return 1, msg, None
|
|
106
|
+
|
|
107
|
+
delete_audit_type_b64 = convert.str2b64str(args.delete_audit_type)
|
|
108
|
+
delete_clmsg_id_b64 = convert.str2b64str(args.delete_clmsg_id)
|
|
109
|
+
delete_clmsg_sdate = args.delete_clmsg_sdate+common.get_tzoffset_str() if args.delete_clmsg_sdate else None
|
|
110
|
+
delete_clmsg_sdate_b64 = convert.str2b64str(delete_clmsg_sdate)
|
|
111
|
+
delete_clmsg_edate = args.delete_clmsg_edate+common.get_tzoffset_str() if args.delete_clmsg_edate else None
|
|
112
|
+
delete_clmsg_edate_b64 = convert.str2b64str(delete_clmsg_edate)
|
|
113
|
+
delete_clmsg_src_b64 = convert.str2b64str(args.delete_clmsg_src)
|
|
114
|
+
delete_clmsg_user_b64 = convert.str2b64str(args.delete_clmsg_user)
|
|
115
|
+
delete_clmsg_body_str = json.dumps(args.delete_clmsg_body, default=common.default_json_enc, ensure_ascii=False) if args.delete_clmsg_body else '{}'
|
|
116
|
+
delete_clmsg_body_b64 = convert.str2b64str(delete_clmsg_body_str)
|
|
117
|
+
delete_clmsg_tag_str = json.dumps(args.delete_clmsg_tag, default=common.default_json_enc, ensure_ascii=False) if args.delete_clmsg_tag else '[]'
|
|
118
|
+
delete_clmsg_tag_b64 = convert.str2b64str(delete_clmsg_tag_str)
|
|
119
|
+
delete_svmsg_id_b64 = convert.str2b64str(args.delete_svmsg_id)
|
|
120
|
+
delete_svmsg_sdate_b64 = convert.str2b64str(args.delete_svmsg_sdate)
|
|
121
|
+
delete_svmsg_edate_b64 = convert.str2b64str(args.delete_svmsg_edate)
|
|
122
|
+
pg_enabled = args.pg_enabled
|
|
123
|
+
pg_host_b64 = convert.str2b64str(args.pg_host)
|
|
124
|
+
pg_port = args.pg_port if isinstance(args.pg_port, int) else None
|
|
125
|
+
pg_user_b64 = convert.str2b64str(args.pg_user)
|
|
126
|
+
pg_password_b64 = convert.str2b64str(args.pg_password)
|
|
127
|
+
pg_dbname_b64 = convert.str2b64str(args.pg_dbname)
|
|
128
|
+
|
|
129
|
+
cl = client.Client(logger, redis_host=args.host, redis_port=args.port, redis_password=args.password, svname=args.svname)
|
|
130
|
+
ret = cl.redis_cli.send_cmd(self.get_svcmd(),
|
|
131
|
+
[delete_audit_type_b64, delete_clmsg_id_b64, delete_clmsg_sdate_b64, delete_clmsg_edate_b64,
|
|
132
|
+
delete_clmsg_src_b64, delete_clmsg_user_b64, delete_clmsg_body_b64, delete_clmsg_tag_b64,
|
|
133
|
+
delete_svmsg_id_b64, delete_svmsg_sdate_b64, delete_svmsg_edate_b64,
|
|
134
|
+
pg_enabled, pg_host_b64, pg_port, pg_user_b64, pg_password_b64, pg_dbname_b64],
|
|
135
|
+
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout)
|
|
136
|
+
common.print_format(ret, args.format, tm, None, False, pf=pf)
|
|
137
|
+
|
|
138
|
+
if 'success' not in ret:
|
|
139
|
+
return 1, ret, cl
|
|
140
|
+
|
|
141
|
+
if 'data' in ret['success']:
|
|
142
|
+
for row in ret['success']['data']:
|
|
143
|
+
try:
|
|
144
|
+
row['clmsg_tag'] = json.loads(row['clmsg_tag'])
|
|
145
|
+
except:
|
|
146
|
+
pass
|
|
147
|
+
try:
|
|
148
|
+
row['clmsg_body'] = json.loads(row['clmsg_body'])
|
|
149
|
+
except:
|
|
150
|
+
pass
|
|
151
|
+
|
|
152
|
+
return 0, ret, cl
|
|
153
|
+
|
|
154
|
+
def is_cluster_redirect(self):
|
|
155
|
+
"""
|
|
156
|
+
クラスター宛のメッセージの場合、メッセージを転送するかどうかを返します
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
bool: メッセージを転送する場合はTrue
|
|
160
|
+
"""
|
|
161
|
+
return False
|
|
162
|
+
|
|
163
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
164
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
165
|
+
"""
|
|
166
|
+
この機能のサーバー側の実行を行います
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
data_dir (Path): データディレクトリ
|
|
170
|
+
logger (logging.Logger): ロガー
|
|
171
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
172
|
+
msg (List[str]): 受信メッセージ
|
|
173
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
int: 終了コード
|
|
177
|
+
"""
|
|
178
|
+
delete_audit_type = convert.b64str2str(msg[2])
|
|
179
|
+
delete_clmsg_id = convert.b64str2str(msg[3])
|
|
180
|
+
delete_clmsg_sdate = convert.b64str2str(msg[4])
|
|
181
|
+
delete_clmsg_edate = convert.b64str2str(msg[5])
|
|
182
|
+
delete_clmsg_src = convert.b64str2str(msg[6])
|
|
183
|
+
delete_clmsg_user = convert.b64str2str(msg[7])
|
|
184
|
+
body = json.loads(convert.b64str2str(msg[8]))
|
|
185
|
+
tags = json.loads(convert.b64str2str(msg[9]))
|
|
186
|
+
delete_svmsg_id = convert.b64str2str(msg[10])
|
|
187
|
+
delete_svmsg_sdate = convert.b64str2str(msg[11])
|
|
188
|
+
delete_svmsg_edate = convert.b64str2str(msg[12])
|
|
189
|
+
pg_enabled = True if msg[13]=='True' else False
|
|
190
|
+
pg_host = convert.b64str2str(msg[14])
|
|
191
|
+
pg_port = int(msg[15]) if msg[15]!='None' else None
|
|
192
|
+
pg_user = convert.b64str2str(msg[16])
|
|
193
|
+
pg_password = convert.b64str2str(msg[17])
|
|
194
|
+
pg_dbname = convert.b64str2str(msg[18])
|
|
195
|
+
st = self.delete(msg[1],
|
|
196
|
+
delete_audit_type, delete_clmsg_id, delete_clmsg_sdate, delete_clmsg_edate,
|
|
197
|
+
delete_clmsg_src, delete_clmsg_user, body, tags,
|
|
198
|
+
delete_svmsg_id, delete_svmsg_sdate, delete_svmsg_edate,
|
|
199
|
+
pg_enabled, pg_host, pg_port, pg_user, pg_password, pg_dbname,
|
|
200
|
+
data_dir, logger, redis_cli)
|
|
201
|
+
return st
|
|
202
|
+
|
|
203
|
+
def delete(self, reskey:str,
|
|
204
|
+
delete_audit_type:str, delete_clmsg_id:str, delete_clmsg_sdate:str, delete_clmsg_edate:str,
|
|
205
|
+
delete_clmsg_src:str, delete_clmsg_user:str, delete_clmsg_body:Dict[str, Any], delete_clmsg_tags:List[str],
|
|
206
|
+
delete_svmsg_id:str, delete_svmsg_sdate:str, delete_svmsg_edate:str,
|
|
207
|
+
pg_enabled:bool, pg_host:str, pg_port:int, pg_user:str, pg_password:str, pg_dbname:str,
|
|
208
|
+
data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient) -> int:
|
|
209
|
+
"""
|
|
210
|
+
監査ログを検索する
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
reskey (str): レスポンスキー
|
|
214
|
+
delete_audit_type (str): 監査の種類
|
|
215
|
+
delete_clmsg_id (str): クライアントメッセージID
|
|
216
|
+
delete_clmsg_sdate (str): クライアントメッセージ発生日時(開始)
|
|
217
|
+
delete_clmsg_edate (str): クライアントメッセージ発生日時(終了)
|
|
218
|
+
delete_clmsg_src (str): クライアントメッセージの発生源
|
|
219
|
+
delete_clmsg_user (str): クライアントメッセージの発生させたユーザー
|
|
220
|
+
delete_clmsg_body (Dict[str, Any]): クライアントメッセージの本文
|
|
221
|
+
delete_clmsg_tags (List[str]): クライアントメッセージのタグ
|
|
222
|
+
delete_svmsg_id (str): サーバーメッセージID
|
|
223
|
+
delete_svmsg_sdate (str): サーバーメッセージ発生日時(開始)
|
|
224
|
+
delete_svmsg_edate (str): サーバーメッセージ発生日時(終了)
|
|
225
|
+
pg_enabled (bool): PostgreSQLを使用する場合はTrue
|
|
226
|
+
pg_host (str): PostgreSQLホスト
|
|
227
|
+
pg_port (int): PostgreSQLポート
|
|
228
|
+
pg_user (str): PostgreSQLユーザー
|
|
229
|
+
pg_password (str): PostgreSQLパスワード
|
|
230
|
+
pg_dbname (str): PostgreSQLデータベース名
|
|
231
|
+
data_dir (Path): データディレクトリ
|
|
232
|
+
logger (logging.Logger): ロガー
|
|
233
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
int: レスポンスコード
|
|
237
|
+
"""
|
|
238
|
+
try:
|
|
239
|
+
with self.initdb(data_dir, logger, pg_enabled, pg_host, pg_port, pg_user, pg_password, pg_dbname) as conn:
|
|
240
|
+
cursor = conn.cursor()
|
|
241
|
+
try:
|
|
242
|
+
sql = f'DELETE FROM audit'
|
|
243
|
+
params = []
|
|
244
|
+
where = []
|
|
245
|
+
if delete_audit_type and delete_audit_type != 'None':
|
|
246
|
+
where.append(f'audit_type={"%s" if pg_enabled else "?"}')
|
|
247
|
+
params.append(delete_audit_type)
|
|
248
|
+
if delete_clmsg_id and delete_clmsg_id != 'None':
|
|
249
|
+
where.append(f'clmsg_id={"%s" if pg_enabled else "?"}')
|
|
250
|
+
params.append(delete_clmsg_id)
|
|
251
|
+
if delete_clmsg_sdate and delete_clmsg_sdate != 'None':
|
|
252
|
+
where.append(f'clmsg_date>={"%s" if pg_enabled else "?"}')
|
|
253
|
+
params.append(delete_clmsg_sdate)
|
|
254
|
+
if delete_clmsg_edate and delete_clmsg_edate != 'None':
|
|
255
|
+
where.append(f'clmsg_date<={"%s" if pg_enabled else "?"}')
|
|
256
|
+
params.append(delete_clmsg_edate)
|
|
257
|
+
if delete_clmsg_src and delete_clmsg_src != 'None':
|
|
258
|
+
where.append(f'clmsg_src LIKE {"%s" if pg_enabled else "?"}')
|
|
259
|
+
params.append(delete_clmsg_src)
|
|
260
|
+
if delete_clmsg_user and delete_clmsg_user != 'None':
|
|
261
|
+
where.append(f'clmsg_user LIKE {"%s" if pg_enabled else "?"}')
|
|
262
|
+
params.append(delete_clmsg_user)
|
|
263
|
+
if delete_clmsg_body:
|
|
264
|
+
if sys.version_info[0] < 3 or sys.version_info[0] >= 3 and sys.version_info[1] < 10:
|
|
265
|
+
raise RuntimeError("Python 3.10 or later is required for JSON support.")
|
|
266
|
+
for key, value in delete_clmsg_body.items():
|
|
267
|
+
where.append(f"clmsg_body->>'{key}' LIKE {'%s' if pg_enabled else '?'}")
|
|
268
|
+
params.append(value)
|
|
269
|
+
if delete_clmsg_tags:
|
|
270
|
+
for tag in delete_clmsg_tags:
|
|
271
|
+
where.append(f"clmsg_tag like {'%s' if pg_enabled else '?'}")
|
|
272
|
+
params.append(f'%{tag}%')
|
|
273
|
+
if delete_svmsg_id and delete_svmsg_id != 'None':
|
|
274
|
+
where.append(f'svmsg_id={"%s" if pg_enabled else "?"}')
|
|
275
|
+
params.append(delete_svmsg_id)
|
|
276
|
+
if delete_svmsg_sdate and delete_svmsg_sdate != 'None':
|
|
277
|
+
where.append(f'svmsg_date>={"%s" if pg_enabled else "?"}')
|
|
278
|
+
params.append(delete_svmsg_sdate)
|
|
279
|
+
if delete_svmsg_edate and delete_svmsg_edate != 'None':
|
|
280
|
+
where.append(f'svmsg_date<={"%s" if pg_enabled else "?"}')
|
|
281
|
+
params.append(delete_svmsg_edate)
|
|
282
|
+
sql += ' WHERE ' + ' AND '.join(where) if len(where)>0 else ''
|
|
283
|
+
cursor.execute(sql, tuple(params))
|
|
284
|
+
delete_count = cursor.rowcount
|
|
285
|
+
conn.commit()
|
|
286
|
+
if delete_count <= 0:
|
|
287
|
+
rescode, msg = (self.RESP_WARN, dict(warn="No data deleted."))
|
|
288
|
+
redis_cli.rpush(reskey, msg)
|
|
289
|
+
return rescode
|
|
290
|
+
else:
|
|
291
|
+
rescode, msg = (self.RESP_SCCESS, dict(success=dict(msg=f"{delete_count} records deleted.", count=delete_count)))
|
|
292
|
+
redis_cli.rpush(reskey, msg)
|
|
293
|
+
return rescode
|
|
294
|
+
finally:
|
|
295
|
+
cursor.close()
|
|
296
|
+
except Exception as e:
|
|
297
|
+
logger.warning(f"Failed to delete: {e}", exc_info=True)
|
|
298
|
+
redis_cli.rpush(reskey, dict(warn=f"Failed to delete: {e}"))
|
|
299
|
+
return self.RESP_WARN
|