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')