Skip to content

Commit d200c4d

Browse files
authored
Merge pull request #1023 from gbregman/devel
Allow listing namespaces for all subsystems
2 parents 9d3a6da + 87097c1 commit d200c4d

File tree

6 files changed

+163
-29
lines changed

6 files changed

+163
-29
lines changed

.github/workflows/build-container.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ jobs:
322322
cephnvmf listener list --subsystem $sub
323323
cephnvmf host list --subsystem $sub
324324
done
325+
cephnvmf namespace list
325326
326327
- name: Run bdevperf
327328
run: |

control/cli.py

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,9 @@ def ns_list(self, args):
18981898
if args.nsid is not None and args.nsid <= 0:
18991899
self.cli.parser.error("nsid value must be positive")
19001900

1901+
if not args.subsystem:
1902+
args.subsystem = GatewayUtils.ALL_SUBSYSTEMS
1903+
19011904
try:
19021905
namespaces_info = self.stub.list_namespaces(pb2.list_namespaces_req(
19031906
subsystem=args.subsystem,
@@ -1909,12 +1912,32 @@ def ns_list(self, args):
19091912

19101913
if args.format == "text" or args.format == "plain":
19111914
if namespaces_info.status == 0:
1912-
if args.nsid and len(namespaces_info.namespaces) > 1:
1913-
err_func(f"Got more than one namespace for NSID {args.nsid}")
1914-
if args.uuid and len(namespaces_info.namespaces) > 1:
1915-
err_func(f"Got more than one namespace for UUID {args.uuid}")
1915+
if args.subsystem != GatewayUtils.ALL_SUBSYSTEMS:
1916+
if args.nsid and len(namespaces_info.namespaces) > 1:
1917+
err_func(f"Got more than one namespace for namespace ID {args.nsid}")
1918+
if args.uuid and len(namespaces_info.namespaces) > 1:
1919+
err_func(f"Got more than one namespace for UUID {args.uuid}")
1920+
if namespaces_info.subsystem_nqn != args.subsystem:
1921+
err_func(f"Got namespaces in subsystem "
1922+
f"{namespaces_info.subsystem_nqn} which is different than the "
1923+
f"requested subsystem {args.subsystem}")
1924+
return errno.ENODEV
19161925
namespaces_list = []
19171926
for ns in namespaces_info.namespaces:
1927+
if args.subsystem == GatewayUtils.ALL_SUBSYSTEMS:
1928+
if not ns.subsystem_nqn:
1929+
err_func(f"Got namespace with ID {ns.nsid} on an unknown subsystem")
1930+
subsys_nqn = "<n/a>"
1931+
else:
1932+
subsys_nqn = ns.subsystem_nqn
1933+
else:
1934+
if ns.subsystem_nqn and ns.subsystem_nqn != args.subsystem:
1935+
err_func(f"Got a namespace with ID {ns.nsid} in subsystem "
1936+
f"{ns.subsystem_nqn} which is different than the "
1937+
f"requested one {args.subsystem}")
1938+
return errno.ENODEV
1939+
subsys_nqn = namespaces_info.subsystem_nqn
1940+
19181941
if args.nsid and args.nsid != ns.nsid:
19191942
err_func(f"Failure listing namespace {args.nsid}: "
19201943
f"Got namespace {ns.nsid} instead")
@@ -1937,7 +1960,8 @@ def ns_list(self, args):
19371960
else:
19381961
visibility = "Restrictive"
19391962

1940-
namespaces_list.append([ns.nsid,
1963+
namespaces_list.append([subsys_nqn,
1964+
ns.nsid,
19411965
break_string(ns.bdev_name, "-", 2),
19421966
f"{ns.rbd_pool_name}/{ns.rbd_image_name}",
19431967
self.format_size(ns.rbd_image_size),
@@ -1956,7 +1980,8 @@ def ns_list(self, args):
19561980
else:
19571981
table_format = "plain"
19581982
namespaces_out = tabulate(namespaces_list,
1959-
headers=["NSID",
1983+
headers=["NQN",
1984+
"NSID",
19601985
"Bdev\nName",
19611986
"RBD\nImage",
19621987
"Image\nSize",
@@ -1975,15 +2000,27 @@ def ns_list(self, args):
19752000
prefix = f"Namespace with UUID {args.uuid} in"
19762001
else:
19772002
prefix = "Namespaces in"
1978-
out_func(f"{prefix} subsystem {args.subsystem}:\n{namespaces_out}")
2003+
if args.subsystem == GatewayUtils.ALL_SUBSYSTEMS:
2004+
out_func(f"{prefix} all subsystems:\n{namespaces_out}")
2005+
else:
2006+
out_func(f"{prefix} subsystem {args.subsystem}:\n{namespaces_out}")
19792007
else:
19802008
if args.nsid:
1981-
out_func(f"No namespace {args.nsid} in subsystem {args.subsystem}")
2009+
if args.subsystem == GatewayUtils.ALL_SUBSYSTEMS:
2010+
out_func(f"No namespace {args.nsid} in any subsystem")
2011+
else:
2012+
out_func(f"No namespace {args.nsid} in subsystem {args.subsystem}")
19822013
elif args.uuid:
1983-
out_func(f"No namespace with UUID {args.uuid} in subsystem "
1984-
f"{args.subsystem}")
2014+
if args.subsystem == GatewayUtils.ALL_SUBSYSTEMS:
2015+
out_func(f"No namespace with UUID {args.uuid} in any subsystem")
2016+
else:
2017+
out_func(f"No namespace with UUID {args.uuid} in subsystem "
2018+
f"{args.subsystem}")
19852019
else:
1986-
out_func(f"No namespaces in subsystem {args.subsystem}")
2020+
if args.subsystem == GatewayUtils.ALL_SUBSYSTEMS:
2021+
out_func("No namespaces in any subsystem")
2022+
else:
2023+
out_func(f"No namespaces in subsystem {args.subsystem}")
19872024
else:
19882025
err_func(f"{namespaces_info.error_message}")
19892026
elif args.format == "json" or args.format == "yaml":
@@ -2433,7 +2470,11 @@ def ns_change_visibility(self, args):
24332470
help="Size in bytes or specified unit (K, KB, M, MB, G, GB, T, TB, P, PB)",
24342471
required=True),
24352472
]
2436-
ns_list_args_list = ns_common_args + [
2473+
ns_list_args_list = [
2474+
argument("--subsystem",
2475+
"-n",
2476+
help="Subsystem NQN",
2477+
required=False),
24372478
argument("--nsid",
24382479
help="Namespace ID",
24392480
type=int),

control/grpc.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2290,14 +2290,14 @@ def list_namespaces(self, request, context=None):
22902290
f"context: {context}{peer_msg}")
22912291

22922292
if not request.subsystem:
2293-
errmsg = "Failure listing namespaces, missing subsystem NQN"
2294-
self.logger.error(errmsg)
2295-
return pb2.namespaces_info(status=errno.EINVAL, error_message=errmsg,
2296-
subsystem_nqn=request.subsystem, namespaces=[])
2293+
request.subsystem = GatewayUtils.ALL_SUBSYSTEMS
22972294

22982295
with self.rpc_lock:
22992296
try:
2300-
ret = rpc_nvmf.nvmf_get_subsystems(self.spdk_rpc_client, nqn=request.subsystem)
2297+
if request.subsystem == GatewayUtils.ALL_SUBSYSTEMS:
2298+
ret = rpc_nvmf.nvmf_get_subsystems(self.spdk_rpc_client)
2299+
else:
2300+
ret = rpc_nvmf.nvmf_get_subsystems(self.spdk_rpc_client, nqn=request.subsystem)
23012301
self.logger.debug(f"list_namespaces: {ret}")
23022302
except Exception as ex:
23032303
errmsg = "Failure listing namespaces"
@@ -2314,17 +2314,19 @@ def list_namespaces(self, request, context=None):
23142314
namespaces = []
23152315
for s in ret:
23162316
try:
2317-
if s["nqn"] != request.subsystem:
2318-
self.logger.warning(f'Got subsystem {s["nqn"]} instead of '
2319-
f'{request.subsystem}, ignore')
2320-
continue
2317+
subsys_nqn = s["nqn"]
2318+
if request.subsystem != GatewayUtils.ALL_SUBSYSTEMS:
2319+
if subsys_nqn != request.subsystem:
2320+
self.logger.warning(f'Got subsystem {subsys_nqn} instead of '
2321+
f'{request.subsystem}, ignore')
2322+
continue
23212323
try:
23222324
ns_list = s["namespaces"]
23232325
except Exception:
23242326
ns_list = []
23252327
pass
23262328
if not ns_list:
2327-
self.subsystem_nsid_bdev_and_uuid.remove_namespace(request.subsystem)
2329+
self.subsystem_nsid_bdev_and_uuid.remove_namespace(subsys_nqn)
23282330
for n in ns_list:
23292331
nsid = n["nsid"]
23302332
bdev_name = n["bdev_name"]
@@ -2341,18 +2343,19 @@ def list_namespaces(self, request, context=None):
23412343
lb_group = n["anagrpid"]
23422344
except KeyError:
23432345
pass
2344-
find_ret = self.subsystem_nsid_bdev_and_uuid.find_namespace(request.subsystem,
2346+
find_ret = self.subsystem_nsid_bdev_and_uuid.find_namespace(subsys_nqn,
23452347
nsid)
23462348
if find_ret.empty():
23472349
self.logger.warning(f"Can't find info of namesapce {nsid} in "
2348-
f"{request.subsystem}. Visibility status "
2350+
f"{subsys_nqn}. Visibility status "
23492351
f"will be inaccurate")
23502352
one_ns = pb2.namespace_cli(nsid=nsid,
23512353
bdev_name=bdev_name,
23522354
uuid=n["uuid"],
23532355
load_balancing_group=lb_group,
23542356
auto_visible=find_ret.auto_visible,
2355-
hosts=find_ret.host_list)
2357+
hosts=find_ret.host_list,
2358+
subsystem_nqn=subsys_nqn)
23562359
with self.rpc_lock:
23572360
ns_bdev = self.get_bdev_info(bdev_name)
23582361
if ns_bdev is None:
@@ -2379,7 +2382,8 @@ def list_namespaces(self, request, context=None):
23792382
self.logger.exception(f"{ns_bdev=} parse error")
23802383
pass
23812384
namespaces.append(one_ns)
2382-
break
2385+
if request.subsystem != GatewayUtils.ALL_SUBSYSTEMS:
2386+
break
23832387
except Exception:
23842388
self.logger.exception(f"{s=} parse error")
23852389
pass

control/proto/gateway.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ message namespace_cli {
523523
uint64 w_mbytes_per_second = 12;
524524
bool auto_visible = 13;
525525
repeated string hosts = 14;
526+
optional string subsystem_nqn = 15;
526527
}
527528

528529
message namespaces_info {

control/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ def get_key_from_value(e_type, val):
5555

5656
class GatewayUtils:
5757
DISCOVERY_NQN = "nqn.2014-08.org.nvmexpress.discovery"
58+
ALL_SUBSYSTEMS = "*"
5859

5960
# We need to enclose IPv6 addresses in brackets before concatenating
6061
# a colon and port number to it

tests/test_cli.py

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
image12 = "mytestdevimage12"
2525
image13 = "mytestdevimage13"
2626
image14 = "mytestdevimage14"
27+
image15 = "mytestdevimage15"
28+
image16 = "mytestdevimage16"
29+
image17 = "mytestdevimage17"
30+
image18 = "mytestdevimage18"
2731
pool = "rbd"
2832
subsystem = "nqn.2016-06.io.spdk:cnode1"
2933
subsystem2 = "nqn.2016-06.io.spdk:cnode2"
@@ -33,6 +37,7 @@
3337
subsystem6 = "nqn.2016-06.io.spdk:cnode6"
3438
subsystem7 = "nqn.2016-06.io.spdk:cnode7"
3539
subsystem8 = "nqn.2016-06.io.spdk:cnode8"
40+
subsystem9 = "nqn.2016-06.io.spdk:cnode9"
3641
subsystemX = "nqn.2016-06.io.spdk:cnodeX"
3742
discovery_nqn = "nqn.2014-08.org.nvmexpress.discovery"
3843
serial = "Ceph00000000000001"
@@ -80,7 +85,7 @@ def gateway(config):
8085
config.config["gateway"]["group"] = group_name
8186
config.config["gateway"]["max_namespaces_with_netmask"] = "3"
8287
config.config["gateway"]["max_hosts_per_namespace"] = "3"
83-
config.config["gateway"]["max_subsystems"] = "3"
88+
config.config["gateway"]["max_subsystems"] = "4"
8489
config.config["gateway"]["max_namespaces"] = "12"
8590
config.config["gateway"]["max_namespaces_per_subsystem"] = "11"
8691
config.config["gateway"]["max_hosts_per_subsystem"] = "4"
@@ -170,7 +175,7 @@ def test_get_gateway_info(self, caplog, gateway):
170175
assert gw_info.spdk_version == spdk_ver
171176
assert gw_info.name == gw.gateway_name
172177
assert gw_info.hostname == gw.host_name
173-
assert gw_info.max_subsystems == 3
178+
assert gw_info.max_subsystems == 4
174179
assert gw_info.max_namespaces == 12
175180
assert gw_info.max_namespaces_per_subsystem == 11
176181
assert gw_info.max_hosts_per_subsystem == 4
@@ -1238,6 +1243,78 @@ def test_create_listener_on_discovery(self, caplog, listener, gateway):
12381243
cli(["listener", "add", "--host-name", host_name] + listener)
12391244
assert "Can't create a listener for a discovery subsystem" in caplog.text
12401245

1246+
def test_list_namespaces_all_subsystems(self, caplog):
1247+
caplog.clear()
1248+
cli(["subsystem", "add", "--subsystem", subsystem9, "--no-group-append"])
1249+
assert f"Adding subsystem {subsystem9}: Successful" in caplog.text
1250+
caplog.clear()
1251+
cli(["namespace", "del", "--subsystem", subsystem, "--nsid", "10"])
1252+
assert f"Deleting namespace 10 from {subsystem}: Successful" in caplog.text
1253+
caplog.clear()
1254+
cli(["namespace", "del", "--subsystem", subsystem, "--nsid", "11"])
1255+
assert f"Deleting namespace 11 from {subsystem}: Successful" in caplog.text
1256+
caplog.clear()
1257+
cli(["namespace", "del", "--subsystem", subsystem, "--nsid", "12"])
1258+
assert f"Deleting namespace 12 from {subsystem}: Successful" in caplog.text
1259+
caplog.clear()
1260+
cli(["namespace", "add", "--subsystem", subsystem9, "--rbd-pool", pool,
1261+
"--rbd-image", image15, "--size", "16MB", "--rbd-create-image"])
1262+
assert f"Adding namespace 1 to {subsystem9}: Successful" in caplog.text
1263+
caplog.clear()
1264+
cli(["namespace", "add", "--subsystem", subsystem9, "--rbd-pool", pool,
1265+
"--rbd-image", image16, "--size", "16MB", "--rbd-create-image"])
1266+
assert f"Adding namespace 2 to {subsystem9}: Successful" in caplog.text
1267+
caplog.clear()
1268+
cli(["--format", "json", "namespace", "list"])
1269+
assert '"subsystem_nqn": "*"' in caplog.text
1270+
assert f'"subsystem_nqn": "{subsystem}"' in caplog.text
1271+
assert f'"subsystem_nqn": "{subsystem9}"' in caplog.text
1272+
assert '"nsid": 1' in caplog.text
1273+
assert '"nsid": 2' in caplog.text
1274+
assert '"nsid": 6' in caplog.text
1275+
caplog.clear()
1276+
cli(["--format", "json", "namespace", "list", "--nsid", "1"])
1277+
assert '"subsystem_nqn": "*"' in caplog.text
1278+
assert f'"subsystem_nqn": "{subsystem}"' in caplog.text
1279+
assert f'"subsystem_nqn": "{subsystem9}"' in caplog.text
1280+
assert '"nsid": 1' in caplog.text
1281+
assert '"nsid": 2' not in caplog.text
1282+
caplog.clear()
1283+
cli(["--format", "json", "namespace", "list", "--nsid", "6"])
1284+
assert '"subsystem_nqn": "*"' in caplog.text
1285+
assert f'"subsystem_nqn": "{subsystem}"' in caplog.text
1286+
assert f'"subsystem_nqn": "{subsystem9}"' not in caplog.text
1287+
assert '"nsid": 6' in caplog.text
1288+
assert '"nsid": 1' not in caplog.text
1289+
assert '"nsid": 2' not in caplog.text
1290+
caplog.clear()
1291+
cli(["--format", "json", "namespace", "list", "--uuid", uuid])
1292+
assert '"subsystem_nqn": "*"' in caplog.text
1293+
assert f'"subsystem_nqn": "{subsystem}"' in caplog.text
1294+
assert f'"subsystem_nqn": "{subsystem9}"' not in caplog.text
1295+
assert f'"uuid": "{uuid}"' in caplog.text
1296+
1297+
def test_namespace_count_updated(self, caplog):
1298+
caplog.clear()
1299+
cli(["subsystem", "add", "--subsystem", subsystem5, "--no-group-append"])
1300+
assert f"Adding subsystem {subsystem5}: Successful" in caplog.text
1301+
caplog.clear()
1302+
cli(["namespace", "add", "--subsystem", subsystem5, "--rbd-pool", pool,
1303+
"--rbd-image", image17, "--size", "16MB", "--rbd-create-image"])
1304+
assert f"Adding namespace 1 to {subsystem5}: Successful" in caplog.text
1305+
caplog.clear()
1306+
cli(["namespace", "add", "--subsystem", subsystem5, "--rbd-pool", pool,
1307+
"--rbd-image", image18, "--size", "16MB", "--rbd-create-image"])
1308+
assert f"Failure adding namespace to {subsystem5}: Maximal number of namespaces (12) " \
1309+
f"has already been reached" in caplog.text
1310+
caplog.clear()
1311+
cli(["subsystem", "del", "--subsystem", subsystem9, "--force"])
1312+
assert f"Deleting subsystem {subsystem9}: Successful" in caplog.text
1313+
caplog.clear()
1314+
cli(["namespace", "add", "--subsystem", subsystem5, "--rbd-pool", pool,
1315+
"--rbd-image", image18, "--size", "16MB", "--rbd-create-image"])
1316+
assert f"Adding namespace 2 to {subsystem5}: Successful" in caplog.text
1317+
12411318

12421319
class TestDelete:
12431320
@pytest.mark.parametrize("host", host_list)
@@ -1392,6 +1469,9 @@ def test_delete_subsystem(self, caplog, gateway):
13921469
cli(["subsystem", "del", "--subsystem", subsystem2])
13931470
assert f"Deleting subsystem {subsystem2}: Successful" in caplog.text
13941471
caplog.clear()
1472+
cli(["subsystem", "del", "--subsystem", subsystem5, "--force"])
1473+
assert f"Deleting subsystem {subsystem5}: Successful" in caplog.text
1474+
caplog.clear()
13951475
cli(["subsystem", "list"])
13961476
assert "No subsystems" in caplog.text
13971477

@@ -1493,8 +1573,14 @@ def test_add_too_many_subsystem(self, caplog, gateway):
14931573
assert f"Adding subsystem {subsystem6}: Successful" in caplog.text
14941574
caplog.clear()
14951575
cli(["subsystem", "add", "--subsystem", subsystem7, "--no-group-append"])
1496-
assert f"Failure creating subsystem {subsystem7}: Maximal number of subsystems (3) has " \
1576+
assert f"Adding subsystem {subsystem7}: Successful" in caplog.text
1577+
caplog.clear()
1578+
cli(["subsystem", "add", "--subsystem", subsystem8, "--no-group-append"])
1579+
assert f"Failure creating subsystem {subsystem8}: Maximal number of subsystems (4) has " \
14971580
f"already been reached" in caplog.text
1581+
caplog.clear()
1582+
cli(["subsystem", "del", "--subsystem", subsystem7])
1583+
assert f"Deleting subsystem {subsystem7}: Successful" in caplog.text
14981584

14991585
def test_too_many_hosts(self, caplog, gateway):
15001586
caplog.clear()

0 commit comments

Comments
 (0)