From 7748a2d4232ec3a8d1104a1a9d9114a907d3b765 Mon Sep 17 00:00:00 2001 From: liuzhe-lz <40699903+liuzhe-lz@users.noreply.github.com> Date: Mon, 29 Jul 2019 16:28:38 +0800 Subject: [PATCH] Let nnictl support stopping by port (#1384) * Support stopping by port * Doc for stopping by port --- docs/en_US/Tutorial/Nnictl.md | 25 +++++++++++++++++++------ docs/zh_CN/Nnictl.md | 30 +++++++++++++++++++++--------- test/naive_test.py | 7 +++++++ tools/nni_cmd/nnictl.py | 1 + tools/nni_cmd/nnictl_utils.py | 29 +++++++++++++++++++---------- 5 files changed, 67 insertions(+), 25 deletions(-) diff --git a/docs/en_US/Tutorial/Nnictl.md b/docs/en_US/Tutorial/Nnictl.md index 67cd049e5c..75b5d3adba 100644 --- a/docs/en_US/Tutorial/Nnictl.md +++ b/docs/en_US/Tutorial/Nnictl.md @@ -114,9 +114,16 @@ Debug mode will disable version check function in Trialkeeper. * Usage ```bash - nnictl stop [id] + nnictl stop [Options] ``` +* Options + + |Name, shorthand|Required|Default|Description| + |------|------|------ |------| + |id| False| |The id of the experiment you want to stop| + |--port, -p| False| |Rest port of the experiment you want to stop| + * Details & Examples 1. If there is no id specified, and there is an experiment running, stop the running experiment, or print error message. @@ -131,15 +138,21 @@ Debug mode will disable version check function in Trialkeeper. nnictl stop [experiment_id] ``` - 3. Users could use 'nnictl stop all' to stop all experiments. + 3. If there is a port specified, and an experiment is running on that port, the experiment will be stopped. + + ```bash + nnictl stop --port 8080 + ``` + + 4. Users could use 'nnictl stop all' to stop all experiments. ```bash nnictl stop all ``` - 4. If the id ends with *, nnictl will stop all experiments whose ids matchs the regular. - 5. If the id does not exist but match the prefix of an experiment id, nnictl will stop the matched experiment. - 6. If the id does not exist but match multiple prefix of the experiment ids, nnictl will give id information. + 5. If the id ends with *, nnictl will stop all experiments whose ids matchs the regular. + 6. If the id does not exist but match the prefix of an experiment id, nnictl will stop the matched experiment. + 7. If the id does not exist but match multiple prefix of the experiment ids, nnictl will give id information. @@ -704,4 +717,4 @@ Debug mode will disable version check function in Trialkeeper. ```bash nnictl --version ``` - \ No newline at end of file + diff --git a/docs/zh_CN/Nnictl.md b/docs/zh_CN/Nnictl.md index 3533a22862..6e4a352228 100644 --- a/docs/zh_CN/Nnictl.md +++ b/docs/zh_CN/Nnictl.md @@ -112,11 +112,18 @@ nnictl 支持的命令: 使用此命令来停止正在运行的单个或多个 Experiment。 * 用法 - + ```bash - nnictl stop [id] + nnictl stop [OPTIONS] ``` +* 选项 + + | 参数及缩写 | 是否必需 | 默认值 | 说明 | + | ----------- | ----- | --- | -------------------------------- | + | id | 否 | | 要停止的 Experiment 标识 | + | --port, -p | 否 | | 要停止的 Experiment 使用的 RESTful 服务端口 | + * 详细信息及样例 1. 如果没有指定 id,并且当前有运行的 Experiment,则会停止该 Experiment,否则会输出错误信息。 @@ -131,19 +138,24 @@ nnictl 支持的命令: ```bash nnictl stop [experiment_id] ``` - - - 3. 可使用 'nnictl stop all' 来停止所有的 Experiment。 + + 3. 如果指定了端口,并且有运行中的 Experiment 正在使用该端口,那么这个 Experiment 将会停止。 + + ```bash + nnictl stop --port 8080 + ```` + + 4. 可使用 'nnictl stop all' 来停止所有的 Experiment。 ```bash nnictl stop all ``` - 4. 如果 id 以 * 结尾,nnictl 会停止所有匹配此通配符的 Experiment。 + 5. 如果 id 以 * 结尾,nnictl 会停止所有匹配此通配符的 Experiment。 - 5. 如果 id 不存在,但匹配了某个Experiment 的 id 前缀,nnictl 会停止匹配的Experiment 。 - 6. 如果 id 不存在,但匹配了多个 Experiment id 的前缀,nnictl 会输出这些 id 的信息。 + 6. 如果 id 不存在,但匹配了某个Experiment 的 id 前缀,nnictl 会停止匹配的Experiment 。 + 7. 如果 id 不存在,但匹配了多个 Experiment id 的前缀,nnictl 会输出这些 id 的信息。 @@ -704,4 +716,4 @@ nnictl 支持的命令: ```bash nnictl --version - ``` \ No newline at end of file + ``` diff --git a/test/naive_test.py b/test/naive_test.py index 9ca9e52858..cdb6119314 100644 --- a/test/naive_test.py +++ b/test/naive_test.py @@ -88,6 +88,7 @@ def stop_experiment_test(): subprocess.run(['nnictl', 'create', '--config', 'tuner_test/local.yml', '--port', '8080'], check=True) subprocess.run(['nnictl', 'create', '--config', 'tuner_test/local.yml', '--port', '8888'], check=True) subprocess.run(['nnictl', 'create', '--config', 'tuner_test/local.yml', '--port', '8989'], check=True) + subprocess.run(['nnictl', 'create', '--config', 'tuner_test/local.yml', '--port', '8990'], check=True) # test cmd 'nnictl stop id` experiment_id = get_experiment_id(EXPERIMENT_URL) @@ -96,6 +97,12 @@ def stop_experiment_test(): snooze() assert not detect_port(8080), '`nnictl stop %s` failed to stop experiments' % experiment_id + # test cmd `nnictl stop --port` + proc = subprocess.run(['nnictl', 'stop', '--port', '8990']) + assert proc.returncode == 0, '`nnictl stop %s` failed with code %d' % (experiment_id, proc.returncode) + snooze() + assert not detect_port(8990), '`nnictl stop %s` failed to stop experiments' % experiment_id + # test cmd `nnictl stop all` proc = subprocess.run(['nnictl', 'stop', 'all']) assert proc.returncode == 0, '`nnictl stop all` failed with code %d' % proc.returncode diff --git a/tools/nni_cmd/nnictl.py b/tools/nni_cmd/nnictl.py index c3289396dd..071382e153 100644 --- a/tools/nni_cmd/nnictl.py +++ b/tools/nni_cmd/nnictl.py @@ -90,6 +90,7 @@ def parse_args(): #parse stop command parser_stop = subparsers.add_parser('stop', help='stop the experiment') parser_stop.add_argument('id', nargs='?', help='the id of experiment, use \'all\' to stop all running experiments') + parser_stop.add_argument('--port', '-p', dest='port', help='the port of restful server') parser_stop.set_defaults(func=stop_experiment) #parse trial command diff --git a/tools/nni_cmd/nnictl_utils.py b/tools/nni_cmd/nnictl_utils.py index a1410a4204..f38be6e733 100644 --- a/tools/nni_cmd/nnictl_utils.py +++ b/tools/nni_cmd/nnictl_utils.py @@ -118,12 +118,14 @@ def check_experiment_id(args, update=True): def parse_ids(args): '''Parse the arguments for nnictl stop - 1.If there is an id specified, return the corresponding id - 2.If there is no id specified, and there is an experiment running, return the id, or return Error - 3.If the id matches an experiment, nnictl will return the id. - 4.If the id ends with *, nnictl will match all ids matchs the regular - 5.If the id does not exist but match the prefix of an experiment id, nnictl will return the matched id - 6.If the id does not exist but match multiple prefix of the experiment ids, nnictl will give id information + 1.If port is provided and id is not specified, return the id who owns the port + 2.If both port and id are provided, return the id if it owns the port, otherwise fail + 3.If there is an id specified, return the corresponding id + 4.If there is no id specified, and there is an experiment running, return the id, or return Error + 5.If the id matches an experiment, nnictl will return the id. + 6.If the id ends with *, nnictl will match all ids matchs the regular + 7.If the id does not exist but match the prefix of an experiment id, nnictl will return the matched id + 8.If the id does not exist but match multiple prefix of the experiment ids, nnictl will give id information ''' update_experiment() experiment_config = Experiments() @@ -140,7 +142,14 @@ def parse_ids(args): elif isinstance(experiment_dict[key], list): # if the config file is old version, remove the configuration from file experiment_config.remove_experiment(key) - if not args.id: + if args.port is not None: + for key in running_experiment_list: + if str(experiment_dict[key]['port']) == args.port: + result_list.append(key) + if args.id and result_list and args.id != result_list[0]: + print_error('Experiment id and resful server port not match') + exit(1) + elif not args.id: if len(running_experiment_list) > 1: print_error('There are multiple experiments, please set the experiment id...') experiment_information = "" @@ -166,8 +175,8 @@ def parse_ids(args): if len(result_list) > 1: print_error(args.id + ' is ambiguous, please choose ' + ' '.join(result_list) ) return None - if not result_list and args.id and args.id != 'all': - print_error('There are no experiments matched, please set correct experiment id...') + if not result_list and ((args.id and args.id != 'all') or args.port): + print_error('There are no experiments matched, please set correct experiment id or restful server port') elif not result_list: print_error('There is no experiment running...') return result_list @@ -665,4 +674,4 @@ def export_trials_data(args): else: print_error('Export failed...') else: - print_error('Restful server is not Running') \ No newline at end of file + print_error('Restful server is not Running')