cmdbox 0.6.3.1__py3-none-any.whl → 0.6.4__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 +16 -7
- cmdbox/app/common.py +2 -2
- cmdbox/app/commons/loghandler.py +4 -1
- cmdbox/app/commons/redis_client.py +1 -1
- cmdbox/app/edge.py +1 -1
- cmdbox/app/feature.py +1 -1
- cmdbox/app/features/cli/cmdbox_audit_createdb.py +224 -224
- cmdbox/app/features/cli/cmdbox_audit_delete.py +4 -4
- cmdbox/app/features/cli/cmdbox_audit_search.py +4 -4
- cmdbox/app/features/cli/cmdbox_audit_write.py +6 -8
- cmdbox/app/features/cli/cmdbox_client_file_copy.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_download.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_list.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_mkdir.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_move.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_remove.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_rmdir.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_upload.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_http.py +7 -6
- cmdbox/app/features/cli/cmdbox_client_server_info.py +4 -4
- cmdbox/app/features/cli/cmdbox_cmd_list.py +3 -3
- cmdbox/app/features/cli/cmdbox_cmd_load.py +5 -5
- cmdbox/app/features/cli/cmdbox_edge_config.py +1 -1
- cmdbox/app/features/cli/cmdbox_edge_start.py +3 -3
- cmdbox/app/features/cli/cmdbox_mcp_client.py +174 -174
- cmdbox/app/features/cli/cmdbox_mcp_proxy.py +96 -96
- cmdbox/app/features/cli/cmdbox_server_list.py +2 -2
- cmdbox/app/features/cli/cmdbox_server_start.py +103 -103
- cmdbox/app/features/cli/cmdbox_server_stop.py +4 -4
- cmdbox/app/features/cli/cmdbox_tts_install.py +307 -0
- cmdbox/app/features/cli/cmdbox_tts_say.py +179 -0
- cmdbox/app/features/cli/cmdbox_tts_start.py +329 -0
- cmdbox/app/features/cli/cmdbox_tts_stop.py +108 -0
- cmdbox/app/features/cli/cmdbox_web_apikey_add.py +91 -106
- cmdbox/app/features/cli/cmdbox_web_apikey_del.py +91 -106
- cmdbox/app/features/cli/cmdbox_web_gencert.py +6 -6
- cmdbox/app/features/cli/cmdbox_web_genpass.py +168 -168
- cmdbox/app/features/cli/cmdbox_web_group_add.py +94 -109
- cmdbox/app/features/cli/cmdbox_web_group_del.py +87 -102
- cmdbox/app/features/cli/cmdbox_web_group_edit.py +94 -109
- cmdbox/app/features/cli/cmdbox_web_group_list.py +87 -102
- cmdbox/app/features/cli/cmdbox_web_start.py +235 -235
- cmdbox/app/features/cli/cmdbox_web_stop.py +72 -72
- cmdbox/app/features/cli/cmdbox_web_user_add.py +104 -119
- cmdbox/app/features/cli/cmdbox_web_user_del.py +87 -102
- cmdbox/app/features/cli/cmdbox_web_user_edit.py +104 -119
- cmdbox/app/features/cli/cmdbox_web_user_list.py +87 -102
- cmdbox/app/filer.py +9 -9
- cmdbox/app/mcp.py +15 -7
- cmdbox/app/options.py +46 -43
- cmdbox/app/server.py +224 -224
- cmdbox/app/web.py +1 -1
- cmdbox/extensions/features.yml +3 -0
- cmdbox/extensions/sample_project/sample/app/features/cli/sample_client_time.py +2 -2
- cmdbox/extensions/sample_project/sample/app/features/cli/sample_server_time.py +3 -3
- cmdbox/licenses/LICENSE_Werkzeug_3_1_1_BSD_License.txt +28 -0
- cmdbox/licenses/LICENSE_absolufy-imports_0_3_1_MIT_License.txt +21 -0
- cmdbox/licenses/LICENSE_cyclopts_3_22_5_Apache_Software_License.txt +201 -0
- cmdbox/licenses/LICENSE_isodate_0_7_2_BSD_License.txt +26 -0
- cmdbox/licenses/LICENSE_lazy-object-proxy_1_11_0_BSD_License.txt +20 -0
- cmdbox/licenses/LICENSE_openapi-core_0_19_5_BSD_License.txt +29 -0
- cmdbox/licenses/LICENSE_openapi-schema-validator_0_6_3_BSD_License.txt +29 -0
- cmdbox/licenses/LICENSE_openapi-spec-validator_0_7_2_Apache_Software_License.txt +201 -0
- cmdbox/licenses/LICENSE_opentelemetry-semantic-conventions_0_57b0_UNKNOWN.txt +201 -0
- cmdbox/licenses/LICENSE_parse_1_20_2_MIT_License.txt +19 -0
- cmdbox/licenses/LICENSE_pathable_0_4_4_Apache_Software_License.txt +201 -0
- cmdbox/licenses/{LICENSE_pillow_11_2_1_UNKNOWN.txt → LICENSE_pillow_11_3_0_UNKNOWN.txt} +393 -3
- cmdbox/licenses/LICENSE_pyperclip_1_9_0_BSD_License.txt +27 -0
- cmdbox/licenses/LICENSE_rfc3339-validator_0_1_4_MIT_License.txt +22 -0
- cmdbox/licenses/LICENSE_rich-rst_1_3_1_MIT_License.txt +7 -0
- cmdbox/licenses/{LICENSE_setuptools_65_5_0_MIT_License.txt → LICENSE_setuptools_80_9_0_UNKNOWN.txt} +0 -2
- cmdbox/licenses/LICENSE_tokenizers_0_21_4_Apache_Software_License.txt +1 -0
- cmdbox/licenses/LICENSE_voicevox_core_0_16_0_MIT.txt +20 -0
- cmdbox/licenses/LICENSE_watchdog_6_0_0_Apache_Software_License.txt +16 -0
- cmdbox/licenses/{LICENSE_typer_0_16_0_MIT_License.txt → LICENSE_wsproto_1_2_0_MIT_License.txt} +2 -2
- cmdbox/licenses/files.txt +56 -42
- cmdbox/logconf_cmdbox.yml +104 -0
- cmdbox/version.py +2 -2
- cmdbox/web/agent.html +8 -2
- cmdbox/web/assets/cmdbox/agent.js +182 -1
- cmdbox/web/assets/cmdbox/common.js +16 -3
- cmdbox/web/assets/cmdbox/svgicon.js +18 -0
- {cmdbox-0.6.3.1.dist-info → cmdbox-0.6.4.dist-info}/METADATA +28 -20
- {cmdbox-0.6.3.1.dist-info → cmdbox-0.6.4.dist-info}/RECORD +124 -114
- {cmdbox-0.6.3.1.dist-info → cmdbox-0.6.4.dist-info}/WHEEL +1 -1
- cmdbox/config.yml +0 -3
- cmdbox/licenses/LICENSE_httptools_0_6_4_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_shellingham_1_5_4_ISC_License-ISCL.txt +0 -13
- cmdbox/licenses/LICENSE_watchfiles_1_1_0_MIT_License.txt +0 -21
- cmdbox/logconf_audit.yml +0 -43
- cmdbox/logconf_client.yml +0 -43
- cmdbox/logconf_edge.yml +0 -43
- cmdbox/logconf_gui.yml +0 -43
- cmdbox/logconf_mcp.yml +0 -43
- cmdbox/logconf_server.yml +0 -43
- cmdbox/logconf_web.yml +0 -43
- /cmdbox/licenses/{LICENSE_Authlib_1_6_0_BSD_License.txt → LICENSE_Authlib_1_6_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_SQLAlchemy_2_0_41_MIT.txt → LICENSE_SQLAlchemy_2_0_42_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_aiohttp_3_12_13_Apache-2_0.txt → LICENSE_aiohttp_3_12_15_Apache-2_0_AND_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_aiosignal_1_3_2_Apache_Software_License.txt → LICENSE_aiosignal_1_4_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_certifi_2025_6_15_Mozilla_Public_License_2_0-MPL_2_0.txt → LICENSE_certifi_2025_7_14_Mozilla_Public_License_2_0-MPL_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_cryptography_45_0_4_Apache-2_0_OR_BSD-3-Clause.txt → LICENSE_cryptography_45_0_5_Apache-2_0_OR_BSD-3-Clause.txt} +0 -0
- /cmdbox/licenses/{LICENSE_docstring_parser_0_16_MIT_License.txt → LICENSE_docstring_parser_0_17_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fastapi_0_115_14_MIT_License.txt → LICENSE_fastapi_0_116_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fastmcp_2_10_1_Apache_Software_License.txt → LICENSE_fastmcp_2_11_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fsspec_2025_5_1_BSD_License.txt → LICENSE_fsspec_2025_7_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-adk_1_5_0_Apache_Software_License.txt → LICENSE_google-adk_1_9_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-api-python-client_2_174_0_Apache_Software_License.txt → LICENSE_google-api-python-client_2_177_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-cloud-aiplatform_1_100_0_Apache_2_0.txt → LICENSE_google-cloud-aiplatform_1_106_0_Apache_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-cloud-bigquery_3_34_0_Apache_Software_License.txt → LICENSE_google-cloud-bigquery_3_35_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-genai_1_23_0_Apache_Software_License.txt → LICENSE_google-genai_1_28_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_grpcio-status_1_73_1_Apache_Software_License.txt → LICENSE_grpcio-status_1_74_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_grpcio_1_73_1_Apache_Software_License.txt → LICENSE_grpcio_1_74_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_huggingface-hub_0_33_1_Apache_Software_License.txt → LICENSE_huggingface-hub_0_34_3_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_opentelemetry-api_1_34_1_Apache_Software_License.txt → LICENSE_jsonschema-path_0_3_4_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_jsonschema_4_24_0_UNKNOWN.txt → LICENSE_jsonschema_4_25_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_litellm_1_73_6_MIT_License.txt → LICENSE_litellm_1_74_12_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_mcp_1_10_1_MIT_License.txt → LICENSE_mcp_1_12_3_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_multidict_6_6_2_Apache_License_2_0.txt → LICENSE_multidict_6_6_3_Apache_License_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_nh3_0_2_21_MIT.txt → LICENSE_nh3_0_3_0_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_numpy_2_3_1_BSD_License.txt → LICENSE_numpy_2_3_2_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_openai_1_93_0_Apache_Software_License.txt → LICENSE_openai_1_98_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_opentelemetry-sdk_1_34_1_Apache_Software_License.txt → LICENSE_opentelemetry-api_1_36_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_opentelemetry-semantic-conventions_0_55b1_Apache_Software_License.txt → LICENSE_opentelemetry-sdk_1_36_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_tokenizers_0_21_2_Apache_Software_License.txt → LICENSE_pywin32_311_Python_Software_Foundation_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_regex_2024_11_6_Apache_Software_License.txt → LICENSE_regex_2025_7_34_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_rich_14_0_0_MIT_License.txt → LICENSE_rich_14_1_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_rpds-py_0_25_1_MIT.txt → LICENSE_rpds-py_0_26_0_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_sse-starlette_2_3_6_BSD_License.txt → LICENSE_sse-starlette_3_0_2_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_starlette_0_46_2_BSD_License.txt → LICENSE_starlette_0_47_2_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_typing_extensions_4_14_0_UNKNOWN.txt → LICENSE_typing_extensions_4_14_1_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_zope_event_5_1_Zope_Public_License.txt → LICENSE_zope_event_5_1_1_Zope_Public_License.txt} +0 -0
- {cmdbox-0.6.3.1.dist-info → cmdbox-0.6.4.dist-info}/entry_points.txt +0 -0
- {cmdbox-0.6.3.1.dist-info → cmdbox-0.6.4.dist-info/licenses}/LICENSE +0 -0
- {cmdbox-0.6.3.1.dist-info → cmdbox-0.6.4.dist-info}/top_level.txt +0 -0
cmdbox/app/options.py
CHANGED
|
@@ -368,20 +368,7 @@ class Options:
|
|
|
368
368
|
"""
|
|
369
369
|
return ftype in self.features_loaded and self.features_loaded[ftype]
|
|
370
370
|
|
|
371
|
-
def
|
|
372
|
-
"""
|
|
373
|
-
フィーチャーファイル(features.yml)を読み込みます。
|
|
374
|
-
|
|
375
|
-
Args:
|
|
376
|
-
ftype (str): フィーチャータイプ。cli又はweb
|
|
377
|
-
func (Any): フィーチャーの処理関数
|
|
378
|
-
appcls (Any): アプリケーションクラス
|
|
379
|
-
ver (Any): バージョンモジュール
|
|
380
|
-
logger (logging.Logger): ロガー
|
|
381
|
-
"""
|
|
382
|
-
# 読込み済みかどうかの判定
|
|
383
|
-
if self.is_features_loaded(ftype):
|
|
384
|
-
return
|
|
371
|
+
def _load_features_yml(self, ver, logger:logging.Logger=None):
|
|
385
372
|
# cmdboxを拡張したアプリをカスタマイズするときのfeatures.ymlを読み込む
|
|
386
373
|
features_yml = Path(f'.{ver.__appid__}/features.yml')
|
|
387
374
|
if not features_yml.exists() or not features_yml.is_file():
|
|
@@ -398,35 +385,51 @@ class Options:
|
|
|
398
385
|
logger.debug(f"features.yml data: {yml}")
|
|
399
386
|
else:
|
|
400
387
|
yml = self.features_yml_data
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
388
|
+
return yml
|
|
389
|
+
return None
|
|
390
|
+
|
|
391
|
+
def load_features_file(self, ftype:str, func, appcls, ver, logger:logging.Logger=None):
|
|
392
|
+
"""
|
|
393
|
+
フィーチャーファイル(features.yml)を読み込みます。
|
|
394
|
+
|
|
395
|
+
Args:
|
|
396
|
+
ftype (str): フィーチャータイプ。cli又はweb
|
|
397
|
+
func (Any): フィーチャーの処理関数
|
|
398
|
+
appcls (Any): アプリケーションクラス
|
|
399
|
+
ver (Any): バージョンモジュール
|
|
400
|
+
logger (logging.Logger): ロガー
|
|
401
|
+
"""
|
|
402
|
+
# 読込み済みかどうかの判定
|
|
403
|
+
if self.is_features_loaded(ftype):
|
|
404
|
+
return
|
|
405
|
+
yml = self._load_features_yml(ver, logger)
|
|
406
|
+
if yml is None: return
|
|
407
|
+
if 'features' not in yml:
|
|
408
|
+
raise Exception('features.yml is invalid. (The root element must be "features".)')
|
|
409
|
+
if ftype not in yml['features']:
|
|
410
|
+
raise Exception(f'features.yml is invalid. (There is no “{ftype}” in the “features” element.)')
|
|
411
|
+
if yml['features'][ftype] is None:
|
|
412
|
+
return
|
|
413
|
+
if type(yml['features'][ftype]) is not list:
|
|
414
|
+
raise Exception(f'features.yml is invalid. (The “features.{ftype} element must be a list. {ftype}={yml["features"][ftype]})')
|
|
415
|
+
for data in yml['features'][ftype]:
|
|
416
|
+
if type(data) is not dict:
|
|
417
|
+
raise Exception(f'features.yml is invalid. (The “features.{ftype}” element must be a list element must be a dictionary. data={data})')
|
|
418
|
+
if 'package' not in data:
|
|
419
|
+
raise Exception(f'features.yml is invalid. (The “package” element must be in the dictionary of the list element of the “features.{ftype}” element. data={data})')
|
|
420
|
+
if 'prefix' not in data:
|
|
421
|
+
raise Exception(f'features.yml is invalid. (The prefix element must be in the dictionary of the list element of the “features.{ftype}” element. data={data})')
|
|
422
|
+
if data['package'] is None or data['package'] == "":
|
|
423
|
+
continue
|
|
424
|
+
if data['prefix'] is None or data['prefix'] == "":
|
|
425
|
+
continue
|
|
426
|
+
exclude_modules = []
|
|
427
|
+
if 'exclude_modules' in data:
|
|
428
|
+
if type(data['exclude_modules']) is not list:
|
|
429
|
+
raise Exception(f'features.yml is invalid. (The “exclude_modules” element must be a list element. data={data})')
|
|
430
|
+
exclude_modules = data['exclude_modules']
|
|
431
|
+
func(data['package'], data['prefix'], exclude_modules, appcls, ver, logger, self.is_features_loaded(ftype))
|
|
432
|
+
self.features_loaded[ftype] = True
|
|
430
433
|
|
|
431
434
|
|
|
432
435
|
def load_features_args(self, args_dict:Dict[str, Any]):
|
cmdbox/app/server.py
CHANGED
|
@@ -1,224 +1,224 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from cmdbox.app import common, filer, feature, options
|
|
3
|
-
from cmdbox.app.commons import redis_client
|
|
4
|
-
from redis import exceptions
|
|
5
|
-
from typing import List, Dict, Any
|
|
6
|
-
import logging
|
|
7
|
-
import redis
|
|
8
|
-
import time
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class Server(filer.Filer):
|
|
12
|
-
|
|
13
|
-
def __init__(self, data_dir:Path, logger:logging.Logger, redis_host:str="localhost", redis_port:int=6379, redis_password:str=None, svname:str='server'):
|
|
14
|
-
"""
|
|
15
|
-
Redisサーバーに接続し、クライアントからのコマンドを受信し実行する
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
data_dir (Path): データフォルダのパス
|
|
19
|
-
logger (logging): ロガー
|
|
20
|
-
redis_host (str): Redisホスト名, by default "localhost"
|
|
21
|
-
redis_port (int): Redisポート番号, by default 6379
|
|
22
|
-
redis_password (str): Redisパスワード, by default None
|
|
23
|
-
svname (str, optional): サーバーのサービス名. by default 'server'
|
|
24
|
-
"""
|
|
25
|
-
super().__init__(data_dir, logger)
|
|
26
|
-
if svname.find('-') >= 0:
|
|
27
|
-
raise ValueError(f"Server name is invalid. '-' is not allowed. svname={svname}")
|
|
28
|
-
self.redis_host = redis_host
|
|
29
|
-
self.redis_port = redis_port
|
|
30
|
-
self.redis_password = redis_password
|
|
31
|
-
self.org_svname = svname
|
|
32
|
-
self.svname = f"{svname}-{common.random_string(size=6)}"
|
|
33
|
-
self.redis_cli = None
|
|
34
|
-
self.sessions:Dict[str, Dict[str, Any]] = {}
|
|
35
|
-
self.is_running = False
|
|
36
|
-
self.train_thread = None
|
|
37
|
-
self.cleaning_interval = 60
|
|
38
|
-
if self.logger.level == logging.DEBUG:
|
|
39
|
-
self.logger.debug(f"server init parameter: data={self.data_dir} -> {self.data_dir.absolute()}")
|
|
40
|
-
self.logger.debug(f"server init parameter: redis_host={self.redis_host}")
|
|
41
|
-
self.logger.debug(f"server init parameter: redis_port={self.redis_port}")
|
|
42
|
-
self.logger.debug(f"server init parameter: redis_password=********")
|
|
43
|
-
self.logger.debug(f"server init parameter: svname={self.svname}")
|
|
44
|
-
self.options = options.Options.getInstance()
|
|
45
|
-
|
|
46
|
-
def __enter__(self):
|
|
47
|
-
self.start_server()
|
|
48
|
-
return self
|
|
49
|
-
|
|
50
|
-
def __exit__(self, a, b, c):
|
|
51
|
-
self.terminate_server()
|
|
52
|
-
|
|
53
|
-
def start_server(self, retry_count:int=20, retry_interval:int=5):
|
|
54
|
-
"""
|
|
55
|
-
サーバー処理を開始する
|
|
56
|
-
"""
|
|
57
|
-
self.is_running = False
|
|
58
|
-
self.retry_count = retry_count
|
|
59
|
-
self.retry_interval = retry_interval
|
|
60
|
-
if self.logger.level == logging.DEBUG:
|
|
61
|
-
self.logger.debug(f"server start parameter: retry_count={self.retry_count}")
|
|
62
|
-
self.logger.debug(f"server start parameter: retry_interval={self.retry_interval}")
|
|
63
|
-
self.redis_cli = redis_client.RedisClient(self.logger, host=self.redis_host, port=self.redis_port, password=self.redis_password, svname=self.svname)
|
|
64
|
-
if self.redis_cli.check_server(find_svname=False, retry_count=self.retry_count, retry_interval=self.retry_interval, outstatus=True):
|
|
65
|
-
self.is_running = True
|
|
66
|
-
self._run_server()
|
|
67
|
-
|
|
68
|
-
def list_server(self) -> Dict[str, List[Dict[str, Any]]]:
|
|
69
|
-
"""
|
|
70
|
-
起動しているサーバーリストを取得する
|
|
71
|
-
|
|
72
|
-
Returns:
|
|
73
|
-
Dict[str, List[Dict[str, Any]]]: サーバーのリスト
|
|
74
|
-
"""
|
|
75
|
-
if self.redis_cli is None:
|
|
76
|
-
self.redis_cli = redis_client.RedisClient(self.logger, host=self.redis_host, port=self.redis_port, password=self.redis_password, svname=self.svname)
|
|
77
|
-
svlist = self.redis_cli.list_server()
|
|
78
|
-
if len(svlist) <= 0:
|
|
79
|
-
return dict(warn="No server is running.")
|
|
80
|
-
return dict(success=svlist)
|
|
81
|
-
|
|
82
|
-
def _clean_server(self):
|
|
83
|
-
"""
|
|
84
|
-
Redisサーバーに残っている停止済みのサーバーキーを削除する
|
|
85
|
-
"""
|
|
86
|
-
hblist = self.redis_cli.keys("hb-*")
|
|
87
|
-
for hb in hblist:
|
|
88
|
-
hb = hb.decode()
|
|
89
|
-
try:
|
|
90
|
-
v = self.redis_cli.hget(hb, 'ctime')
|
|
91
|
-
if v is None:
|
|
92
|
-
continue
|
|
93
|
-
except exceptions.ResponseError:
|
|
94
|
-
self.logger.warning(f"Failed to get ctime. {hb}", exc_info=True)
|
|
95
|
-
continue
|
|
96
|
-
tm = time.time() - float(v)
|
|
97
|
-
if tm > self.cleaning_interval:
|
|
98
|
-
self.redis_cli.delete(hb)
|
|
99
|
-
self.redis_cli.delete(hb.replace("hb-", "sv-"))
|
|
100
|
-
|
|
101
|
-
def _clean_reskey(self):
|
|
102
|
-
"""
|
|
103
|
-
Redisサーバーに残っている停止済みのクライアントキーを削除する
|
|
104
|
-
"""
|
|
105
|
-
rlist = self.redis_cli.keys("cl-*")
|
|
106
|
-
for reskey in rlist:
|
|
107
|
-
try:
|
|
108
|
-
tm = int(reskey.decode().split("-")[2])
|
|
109
|
-
if time.time() - tm > self.cleaning_interval:
|
|
110
|
-
self.redis_cli.delete(reskey)
|
|
111
|
-
except Exception as e:
|
|
112
|
-
self.redis_cli.delete(reskey)
|
|
113
|
-
|
|
114
|
-
def _run_server(self):
|
|
115
|
-
self.logger.info(f"start server. svname={self.svname}")
|
|
116
|
-
ltime = time.time()
|
|
117
|
-
receive_cnt = 0
|
|
118
|
-
sccess_cnt = 0
|
|
119
|
-
warn_cnt = 0
|
|
120
|
-
error_cnt = 0
|
|
121
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'receive_cnt', receive_cnt)
|
|
122
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'sccess_cnt', sccess_cnt)
|
|
123
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'warn_cnt', warn_cnt)
|
|
124
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'error_cnt', error_cnt)
|
|
125
|
-
|
|
126
|
-
def _publish(msg_str):
|
|
127
|
-
# 各サーバーにメッセージを配布する
|
|
128
|
-
hblist = self.redis_cli.keys(f"hb-{self.org_svname}-*")
|
|
129
|
-
for hb in hblist:
|
|
130
|
-
hb = hb.decode()
|
|
131
|
-
sv = hb.replace("hb-", "sv-")
|
|
132
|
-
self.redis_cli.rpush(sv, msg_str)
|
|
133
|
-
|
|
134
|
-
while self.is_running:
|
|
135
|
-
try:
|
|
136
|
-
msg = None
|
|
137
|
-
# ブロッキングリストから要素を取り出す
|
|
138
|
-
ctime = time.time()
|
|
139
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'ctime', ctime)
|
|
140
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'status', 'ready')
|
|
141
|
-
result = self.redis_cli.blpop(self.redis_cli.svname)
|
|
142
|
-
if ctime - ltime > self.cleaning_interval:
|
|
143
|
-
self._clean_server()
|
|
144
|
-
self._clean_reskey()
|
|
145
|
-
ltime = ctime
|
|
146
|
-
to_cluster = False
|
|
147
|
-
if result is None or len(result) <= 0:
|
|
148
|
-
# クラスター宛メッセージがあるか確認する
|
|
149
|
-
result = self.redis_cli.blpop(f"sv-{self.org_svname}")
|
|
150
|
-
if result is None or len(result) <= 0:
|
|
151
|
-
time.sleep(1)
|
|
152
|
-
continue
|
|
153
|
-
to_cluster = True
|
|
154
|
-
msg_str = result[1].decode()
|
|
155
|
-
msg = msg_str.split(' ')
|
|
156
|
-
if len(msg) <= 0:
|
|
157
|
-
time.sleep(1)
|
|
158
|
-
continue
|
|
159
|
-
|
|
160
|
-
st = None
|
|
161
|
-
receive_cnt += 1
|
|
162
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'receive_cnt', receive_cnt)
|
|
163
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'status', 'processing')
|
|
164
|
-
|
|
165
|
-
svcmd_feature:feature.Feature = self.options.get_svcmd_feature(msg[0])
|
|
166
|
-
if svcmd_feature is not None:
|
|
167
|
-
if to_cluster and svcmd_feature.is_cluster_redirect():
|
|
168
|
-
_publish(msg_str)
|
|
169
|
-
continue
|
|
170
|
-
if msg[0] == 'stop_server':
|
|
171
|
-
self.is_running = False
|
|
172
|
-
st = svcmd_feature.svrun(self.data_dir, self.logger, self.redis_cli, msg, self.sessions)
|
|
173
|
-
else:
|
|
174
|
-
self.logger.warning(f"Unknown command {msg}")
|
|
175
|
-
st = self.RESP_WARN
|
|
176
|
-
|
|
177
|
-
if st==self.
|
|
178
|
-
sccess_cnt += 1
|
|
179
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'sccess_cnt', sccess_cnt)
|
|
180
|
-
elif st==self.RESP_WARN:
|
|
181
|
-
warn_cnt += 1
|
|
182
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'warn_cnt', warn_cnt)
|
|
183
|
-
elif st==self.RESP_ERROR:
|
|
184
|
-
error_cnt += 1
|
|
185
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'error_cnt', error_cnt)
|
|
186
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'ctime', time.time())
|
|
187
|
-
except exceptions.TimeoutError:
|
|
188
|
-
pass
|
|
189
|
-
except exceptions.ConnectionError as e:
|
|
190
|
-
self.logger.warning(f"Connection to the server was lost. {e}", exc_info=True)
|
|
191
|
-
if not self.redis_cli.check_server(find_svname=False, retry_count=self.retry_count, retry_interval=self.retry_interval, outstatus=True):
|
|
192
|
-
self.is_running = False
|
|
193
|
-
break
|
|
194
|
-
except OSError as e:
|
|
195
|
-
self.logger.warning(f"OSError. {e}. This message is not executable in the server environment. ({msg})", exc_info=True)
|
|
196
|
-
if msg is not None and len(msg) > 1:
|
|
197
|
-
self.redis_cli.rpush(msg[1], dict(warn=f"OSError. {e}. This message is not executable in the server environment. ({msg[0]})"))
|
|
198
|
-
error_cnt += 1
|
|
199
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'error_cnt', error_cnt)
|
|
200
|
-
pass
|
|
201
|
-
except IndexError as e:
|
|
202
|
-
self.logger.warning(f"IndexError. {e}. The message received by the server is invalid. ({msg})", exc_info=True)
|
|
203
|
-
if msg is not None and len(msg) > 1:
|
|
204
|
-
self.redis_cli.rpush(msg[1], dict(warn=f"IndexError. {e}. The message received by the server is invalid. ({msg[0]})"))
|
|
205
|
-
error_cnt += 1
|
|
206
|
-
self.redis_cli.hset(self.redis_cli.hbname, 'error_cnt', error_cnt)
|
|
207
|
-
pass
|
|
208
|
-
except KeyboardInterrupt as e:
|
|
209
|
-
self.is_running = False
|
|
210
|
-
break
|
|
211
|
-
except Exception as e:
|
|
212
|
-
self.logger.warning(f"Unknown error occurred. {e}. Service will be stopped due to unknown cause.({msg})", exc_info=True)
|
|
213
|
-
self.is_running = False
|
|
214
|
-
break
|
|
215
|
-
self.redis_cli.delete(self.redis_cli.svname)
|
|
216
|
-
self.redis_cli.delete(self.redis_cli.hbname)
|
|
217
|
-
self.logger.info(f"stop server. svname={self.redis_cli.svname}")
|
|
218
|
-
|
|
219
|
-
def terminate_server(self):
|
|
220
|
-
"""
|
|
221
|
-
サーバー処理を終了する
|
|
222
|
-
"""
|
|
223
|
-
self.redis_cli.close()
|
|
224
|
-
self.logger.info(f"terminate server.")
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from cmdbox.app import common, filer, feature, options
|
|
3
|
+
from cmdbox.app.commons import redis_client
|
|
4
|
+
from redis import exceptions
|
|
5
|
+
from typing import List, Dict, Any
|
|
6
|
+
import logging
|
|
7
|
+
import redis
|
|
8
|
+
import time
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Server(filer.Filer):
|
|
12
|
+
|
|
13
|
+
def __init__(self, data_dir:Path, logger:logging.Logger, redis_host:str="localhost", redis_port:int=6379, redis_password:str=None, svname:str='server'):
|
|
14
|
+
"""
|
|
15
|
+
Redisサーバーに接続し、クライアントからのコマンドを受信し実行する
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
data_dir (Path): データフォルダのパス
|
|
19
|
+
logger (logging): ロガー
|
|
20
|
+
redis_host (str): Redisホスト名, by default "localhost"
|
|
21
|
+
redis_port (int): Redisポート番号, by default 6379
|
|
22
|
+
redis_password (str): Redisパスワード, by default None
|
|
23
|
+
svname (str, optional): サーバーのサービス名. by default 'server'
|
|
24
|
+
"""
|
|
25
|
+
super().__init__(data_dir, logger)
|
|
26
|
+
if svname.find('-') >= 0:
|
|
27
|
+
raise ValueError(f"Server name is invalid. '-' is not allowed. svname={svname}")
|
|
28
|
+
self.redis_host = redis_host
|
|
29
|
+
self.redis_port = redis_port
|
|
30
|
+
self.redis_password = redis_password
|
|
31
|
+
self.org_svname = svname
|
|
32
|
+
self.svname = f"{svname}-{common.random_string(size=6)}"
|
|
33
|
+
self.redis_cli = None
|
|
34
|
+
self.sessions:Dict[str, Dict[str, Any]] = {}
|
|
35
|
+
self.is_running = False
|
|
36
|
+
self.train_thread = None
|
|
37
|
+
self.cleaning_interval = 60
|
|
38
|
+
if self.logger.level == logging.DEBUG:
|
|
39
|
+
self.logger.debug(f"server init parameter: data={self.data_dir} -> {self.data_dir.absolute()}")
|
|
40
|
+
self.logger.debug(f"server init parameter: redis_host={self.redis_host}")
|
|
41
|
+
self.logger.debug(f"server init parameter: redis_port={self.redis_port}")
|
|
42
|
+
self.logger.debug(f"server init parameter: redis_password=********")
|
|
43
|
+
self.logger.debug(f"server init parameter: svname={self.svname}")
|
|
44
|
+
self.options = options.Options.getInstance()
|
|
45
|
+
|
|
46
|
+
def __enter__(self):
|
|
47
|
+
self.start_server()
|
|
48
|
+
return self
|
|
49
|
+
|
|
50
|
+
def __exit__(self, a, b, c):
|
|
51
|
+
self.terminate_server()
|
|
52
|
+
|
|
53
|
+
def start_server(self, retry_count:int=20, retry_interval:int=5):
|
|
54
|
+
"""
|
|
55
|
+
サーバー処理を開始する
|
|
56
|
+
"""
|
|
57
|
+
self.is_running = False
|
|
58
|
+
self.retry_count = retry_count
|
|
59
|
+
self.retry_interval = retry_interval
|
|
60
|
+
if self.logger.level == logging.DEBUG:
|
|
61
|
+
self.logger.debug(f"server start parameter: retry_count={self.retry_count}")
|
|
62
|
+
self.logger.debug(f"server start parameter: retry_interval={self.retry_interval}")
|
|
63
|
+
self.redis_cli = redis_client.RedisClient(self.logger, host=self.redis_host, port=self.redis_port, password=self.redis_password, svname=self.svname)
|
|
64
|
+
if self.redis_cli.check_server(find_svname=False, retry_count=self.retry_count, retry_interval=self.retry_interval, outstatus=True):
|
|
65
|
+
self.is_running = True
|
|
66
|
+
self._run_server()
|
|
67
|
+
|
|
68
|
+
def list_server(self) -> Dict[str, List[Dict[str, Any]]]:
|
|
69
|
+
"""
|
|
70
|
+
起動しているサーバーリストを取得する
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
Dict[str, List[Dict[str, Any]]]: サーバーのリスト
|
|
74
|
+
"""
|
|
75
|
+
if self.redis_cli is None:
|
|
76
|
+
self.redis_cli = redis_client.RedisClient(self.logger, host=self.redis_host, port=self.redis_port, password=self.redis_password, svname=self.svname)
|
|
77
|
+
svlist = self.redis_cli.list_server()
|
|
78
|
+
if len(svlist) <= 0:
|
|
79
|
+
return dict(warn="No server is running.")
|
|
80
|
+
return dict(success=svlist)
|
|
81
|
+
|
|
82
|
+
def _clean_server(self):
|
|
83
|
+
"""
|
|
84
|
+
Redisサーバーに残っている停止済みのサーバーキーを削除する
|
|
85
|
+
"""
|
|
86
|
+
hblist = self.redis_cli.keys("hb-*")
|
|
87
|
+
for hb in hblist:
|
|
88
|
+
hb = hb.decode()
|
|
89
|
+
try:
|
|
90
|
+
v = self.redis_cli.hget(hb, 'ctime')
|
|
91
|
+
if v is None:
|
|
92
|
+
continue
|
|
93
|
+
except exceptions.ResponseError:
|
|
94
|
+
self.logger.warning(f"Failed to get ctime. {hb}", exc_info=True)
|
|
95
|
+
continue
|
|
96
|
+
tm = time.time() - float(v)
|
|
97
|
+
if tm > self.cleaning_interval:
|
|
98
|
+
self.redis_cli.delete(hb)
|
|
99
|
+
self.redis_cli.delete(hb.replace("hb-", "sv-"))
|
|
100
|
+
|
|
101
|
+
def _clean_reskey(self):
|
|
102
|
+
"""
|
|
103
|
+
Redisサーバーに残っている停止済みのクライアントキーを削除する
|
|
104
|
+
"""
|
|
105
|
+
rlist = self.redis_cli.keys("cl-*")
|
|
106
|
+
for reskey in rlist:
|
|
107
|
+
try:
|
|
108
|
+
tm = int(reskey.decode().split("-")[2])
|
|
109
|
+
if time.time() - tm > self.cleaning_interval:
|
|
110
|
+
self.redis_cli.delete(reskey)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
self.redis_cli.delete(reskey)
|
|
113
|
+
|
|
114
|
+
def _run_server(self):
|
|
115
|
+
self.logger.info(f"start server. svname={self.svname}")
|
|
116
|
+
ltime = time.time()
|
|
117
|
+
receive_cnt = 0
|
|
118
|
+
sccess_cnt = 0
|
|
119
|
+
warn_cnt = 0
|
|
120
|
+
error_cnt = 0
|
|
121
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'receive_cnt', receive_cnt)
|
|
122
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'sccess_cnt', sccess_cnt)
|
|
123
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'warn_cnt', warn_cnt)
|
|
124
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'error_cnt', error_cnt)
|
|
125
|
+
|
|
126
|
+
def _publish(msg_str):
|
|
127
|
+
# 各サーバーにメッセージを配布する
|
|
128
|
+
hblist = self.redis_cli.keys(f"hb-{self.org_svname}-*")
|
|
129
|
+
for hb in hblist:
|
|
130
|
+
hb = hb.decode()
|
|
131
|
+
sv = hb.replace("hb-", "sv-")
|
|
132
|
+
self.redis_cli.rpush(sv, msg_str)
|
|
133
|
+
|
|
134
|
+
while self.is_running:
|
|
135
|
+
try:
|
|
136
|
+
msg = None
|
|
137
|
+
# ブロッキングリストから要素を取り出す
|
|
138
|
+
ctime = time.time()
|
|
139
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'ctime', ctime)
|
|
140
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'status', 'ready')
|
|
141
|
+
result = self.redis_cli.blpop(self.redis_cli.svname)
|
|
142
|
+
if ctime - ltime > self.cleaning_interval:
|
|
143
|
+
self._clean_server()
|
|
144
|
+
self._clean_reskey()
|
|
145
|
+
ltime = ctime
|
|
146
|
+
to_cluster = False
|
|
147
|
+
if result is None or len(result) <= 0:
|
|
148
|
+
# クラスター宛メッセージがあるか確認する
|
|
149
|
+
result = self.redis_cli.blpop(f"sv-{self.org_svname}")
|
|
150
|
+
if result is None or len(result) <= 0:
|
|
151
|
+
time.sleep(1)
|
|
152
|
+
continue
|
|
153
|
+
to_cluster = True
|
|
154
|
+
msg_str = result[1].decode()
|
|
155
|
+
msg = msg_str.split(' ')
|
|
156
|
+
if len(msg) <= 0:
|
|
157
|
+
time.sleep(1)
|
|
158
|
+
continue
|
|
159
|
+
|
|
160
|
+
st = None
|
|
161
|
+
receive_cnt += 1
|
|
162
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'receive_cnt', receive_cnt)
|
|
163
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'status', 'processing')
|
|
164
|
+
|
|
165
|
+
svcmd_feature:feature.Feature = self.options.get_svcmd_feature(msg[0])
|
|
166
|
+
if svcmd_feature is not None:
|
|
167
|
+
if to_cluster and svcmd_feature.is_cluster_redirect():
|
|
168
|
+
_publish(msg_str)
|
|
169
|
+
continue
|
|
170
|
+
if msg[0] == 'stop_server':
|
|
171
|
+
self.is_running = False
|
|
172
|
+
st = svcmd_feature.svrun(self.data_dir, self.logger, self.redis_cli, msg, self.sessions)
|
|
173
|
+
else:
|
|
174
|
+
self.logger.warning(f"Unknown command {msg}")
|
|
175
|
+
st = self.RESP_WARN
|
|
176
|
+
|
|
177
|
+
if st==self.RESP_SUCCESS:
|
|
178
|
+
sccess_cnt += 1
|
|
179
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'sccess_cnt', sccess_cnt)
|
|
180
|
+
elif st==self.RESP_WARN:
|
|
181
|
+
warn_cnt += 1
|
|
182
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'warn_cnt', warn_cnt)
|
|
183
|
+
elif st==self.RESP_ERROR:
|
|
184
|
+
error_cnt += 1
|
|
185
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'error_cnt', error_cnt)
|
|
186
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'ctime', time.time())
|
|
187
|
+
except exceptions.TimeoutError:
|
|
188
|
+
pass
|
|
189
|
+
except exceptions.ConnectionError as e:
|
|
190
|
+
self.logger.warning(f"Connection to the server was lost. {e}", exc_info=True)
|
|
191
|
+
if not self.redis_cli.check_server(find_svname=False, retry_count=self.retry_count, retry_interval=self.retry_interval, outstatus=True):
|
|
192
|
+
self.is_running = False
|
|
193
|
+
break
|
|
194
|
+
except OSError as e:
|
|
195
|
+
self.logger.warning(f"OSError. {e}. This message is not executable in the server environment. ({msg})", exc_info=True)
|
|
196
|
+
if msg is not None and len(msg) > 1:
|
|
197
|
+
self.redis_cli.rpush(msg[1], dict(warn=f"OSError. {e}. This message is not executable in the server environment. ({msg[0]})"))
|
|
198
|
+
error_cnt += 1
|
|
199
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'error_cnt', error_cnt)
|
|
200
|
+
pass
|
|
201
|
+
except IndexError as e:
|
|
202
|
+
self.logger.warning(f"IndexError. {e}. The message received by the server is invalid. ({msg})", exc_info=True)
|
|
203
|
+
if msg is not None and len(msg) > 1:
|
|
204
|
+
self.redis_cli.rpush(msg[1], dict(warn=f"IndexError. {e}. The message received by the server is invalid. ({msg[0]})"))
|
|
205
|
+
error_cnt += 1
|
|
206
|
+
self.redis_cli.hset(self.redis_cli.hbname, 'error_cnt', error_cnt)
|
|
207
|
+
pass
|
|
208
|
+
except KeyboardInterrupt as e:
|
|
209
|
+
self.is_running = False
|
|
210
|
+
break
|
|
211
|
+
except Exception as e:
|
|
212
|
+
self.logger.warning(f"Unknown error occurred. {e}. Service will be stopped due to unknown cause.({msg})", exc_info=True)
|
|
213
|
+
self.is_running = False
|
|
214
|
+
break
|
|
215
|
+
self.redis_cli.delete(self.redis_cli.svname)
|
|
216
|
+
self.redis_cli.delete(self.redis_cli.hbname)
|
|
217
|
+
self.logger.info(f"stop server. svname={self.redis_cli.svname}")
|
|
218
|
+
|
|
219
|
+
def terminate_server(self):
|
|
220
|
+
"""
|
|
221
|
+
サーバー処理を終了する
|
|
222
|
+
"""
|
|
223
|
+
self.redis_cli.close()
|
|
224
|
+
self.logger.info(f"terminate server.")
|
cmdbox/app/web.py
CHANGED
|
@@ -475,7 +475,7 @@ class Web:
|
|
|
475
475
|
for u in signin_data['users']:
|
|
476
476
|
if u['uid'] == user['uid']:
|
|
477
477
|
u['name'] = user['name']
|
|
478
|
-
if 'password' in user and user['password'] != '':
|
|
478
|
+
if 'password' in user and user['password'] is not None and user['password'] != '':
|
|
479
479
|
jadge, msg = self.signin.check_password_policy(user['name'], u['password'], user['password'])
|
|
480
480
|
if not jadge:
|
|
481
481
|
raise ValueError(msg)
|
cmdbox/extensions/features.yml
CHANGED
|
@@ -60,8 +60,8 @@ class ClientTime(feature.Feature):
|
|
|
60
60
|
ret = dict(success=dict(data=dt.strftime('%Y-%m-%d %H:%M:%S')))
|
|
61
61
|
common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
62
62
|
if 'success' not in ret:
|
|
63
|
-
return
|
|
64
|
-
return
|
|
63
|
+
return self.RESP_WARN, ret, None
|
|
64
|
+
return self.RESP_SUCCESS, ret, None
|
|
65
65
|
|
|
66
66
|
def edgerun(self, opt, tool, logger, timeout, prevres = None):
|
|
67
67
|
"""
|
|
@@ -92,8 +92,8 @@ class ServerTime(feature.Feature):
|
|
|
92
92
|
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout)
|
|
93
93
|
common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
94
94
|
if 'success' not in ret:
|
|
95
|
-
return
|
|
96
|
-
return
|
|
95
|
+
return self.RESP_WARN, ret, None
|
|
96
|
+
return self.RESP_SUCCESS, ret, None
|
|
97
97
|
|
|
98
98
|
def is_cluster_redirect(self):
|
|
99
99
|
"""
|
|
@@ -124,7 +124,7 @@ class ServerTime(feature.Feature):
|
|
|
124
124
|
dt = datetime.datetime.now(tz)
|
|
125
125
|
ret = dict(success=dict(data=dt.strftime('%Y-%m-%d %H:%M:%S')))
|
|
126
126
|
redis_cli.rpush(msg[1], ret)
|
|
127
|
-
return self.
|
|
127
|
+
return self.RESP_SUCCESS
|
|
128
128
|
|
|
129
129
|
def edgerun(self, opt, tool, logger, timeout, prevres = None):
|
|
130
130
|
"""
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Copyright 2007 Pallets
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
|
4
|
+
modification, are permitted provided that the following conditions are
|
|
5
|
+
met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
|
12
|
+
documentation and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
15
|
+
contributors may be used to endorse or promote products derived from
|
|
16
|
+
this software without specific prior written permission.
|
|
17
|
+
|
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
19
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
20
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
21
|
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
22
|
+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
23
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
24
|
+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
25
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
26
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
27
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
28
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|