]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/pybind/test_ceph_argparse.py
2 # -*- mode:python; tab-width:4; indent-tabs-mode:t; coding:utf-8 -*-
3 # vim: ts=4 sw=4 smarttab expandtab fileencoding=utf-8
5 # Ceph - scalable distributed file system
7 # Copyright (C) 2013,2014 Cloudwatt <libre.licensing@cloudwatt.com>
8 # Copyright (C) 2014 Red Hat <contact@redhat.com>
10 # Author: Loic Dachary <loic@dachary.org>
12 # This library is free software; you can redistribute it and/or
13 # modify it under the terms of the GNU Lesser General Public
14 # License as published by the Free Software Foundation; either
15 # version 2.1 of the License, or (at your option) any later version.
18 from nose
.tools
import eq_
as eq
19 from nose
.tools
import *
20 from unittest
import TestCase
22 from ceph_argparse
import validate_command
, parse_json_funcsigs
, validate
, \
23 parse_funcsig
, ArgumentError
, ArgumentTooFew
, ArgumentMissing
, \
24 ArgumentNumber
, ArgumentValid
33 from StringIO
import StringIO
35 from io
import StringIO
37 def get_command_descriptions(what
):
38 CEPH_BIN
= os
.environ
['CEPH_BIN']
41 return os
.popen(CEPH_BIN
+ "/get_command_descriptions " + "--" + what
).read()
43 def test_parse_json_funcsigs():
44 commands
= get_command_descriptions("all")
45 cmd_json
= parse_json_funcsigs(commands
, 'cli')
47 # syntax error https://github.com/ceph/ceph/pull/585
48 commands
= get_command_descriptions("pull585")
49 assert_raises(TypeError, parse_json_funcsigs
, commands
, 'cli')
51 sigdict
= parse_json_funcsigs(get_command_descriptions("all"), 'cli')
56 def assert_valid_command(self
, args
):
57 result
= validate_command(sigdict
, args
)
58 assert_not_in(result
, [{}, None])
60 def check_1_natural_arg(self
, prefix
, command
):
61 self
.assert_valid_command([prefix
, command
, '1'])
62 assert_equal({}, validate_command(sigdict
, [prefix
, command
]))
63 assert_equal({}, validate_command(sigdict
, [prefix
, command
, '-1']))
64 assert_equal({}, validate_command(sigdict
, [prefix
, command
, '1',
67 def check_0_or_1_natural_arg(self
, prefix
, command
):
68 self
.assert_valid_command([prefix
, command
, '1'])
69 self
.assert_valid_command([prefix
, command
])
70 assert_equal({}, validate_command(sigdict
, [prefix
, command
, '-1']))
71 assert_equal({}, validate_command(sigdict
, [prefix
, command
, '1',
74 def check_1_string_arg(self
, prefix
, command
):
75 assert_equal({}, validate_command(sigdict
, [prefix
, command
]))
76 self
.assert_valid_command([prefix
, command
, 'string'])
77 assert_equal({}, validate_command(sigdict
, [prefix
,
82 def check_0_or_1_string_arg(self
, prefix
, command
):
83 self
.assert_valid_command([prefix
, command
, 'string'])
84 self
.assert_valid_command([prefix
, command
])
85 assert_equal({}, validate_command(sigdict
, [prefix
, command
, 'string',
88 def check_1_or_more_string_args(self
, prefix
, command
):
89 assert_equal({}, validate_command(sigdict
, [prefix
,
91 self
.assert_valid_command([prefix
,
94 self
.assert_valid_command([prefix
,
99 def check_no_arg(self
, prefix
, command
):
100 self
.assert_valid_command([prefix
,
102 assert_equal({}, validate_command(sigdict
, [prefix
,
106 def capture_output(self
, args
, stdout
=None, stderr
=None):
113 ret
= validate_command(sigdict
, args
)
115 stdout
= stdout
.getvalue().strip()
117 stderr
= stderr
.getvalue().strip()
118 return ret
, stdout
, stderr
123 def test_non_ascii_in_non_options(self
):
124 # ArgumentPrefix("no match for {0}".format(s)) is not able to convert
125 # unicode str parameter into str. and validate_command() should not
127 assert_equal({}, validate_command(sigdict
, [u
'章鱼和鱿鱼']))
128 assert_equal({}, validate_command(sigdict
, [u
'–w']))
129 # actually we always pass unicode strings to validate_command() in "ceph"
130 # CLI, but we also use bytestrings in our tests, so make sure it does not
132 assert_equal({}, validate_command(sigdict
, ['章鱼和鱿鱼']))
133 assert_equal({}, validate_command(sigdict
, ['–w']))
136 class TestPG(TestArgparse
):
139 self
.assert_valid_command(['pg', 'stat'])
141 def test_getmap(self
):
142 self
.assert_valid_command(['pg', 'getmap'])
145 self
.assert_valid_command(['pg', 'dump'])
146 self
.assert_valid_command(['pg', 'dump',
155 assert_equal({}, validate_command(sigdict
, ['pg', 'dump', 'invalid']))
157 def test_dump_json(self
):
158 self
.assert_valid_command(['pg', 'dump_json'])
159 self
.assert_valid_command(['pg', 'dump_json',
166 assert_equal({}, validate_command(sigdict
, ['pg', 'dump_json',
169 def test_dump_pools_json(self
):
170 self
.assert_valid_command(['pg', 'dump_pools_json'])
172 def test_dump_pools_stuck(self
):
173 self
.assert_valid_command(['pg', 'dump_stuck'])
174 self
.assert_valid_command(['pg', 'dump_stuck',
178 assert_equal({}, validate_command(sigdict
, ['pg', 'dump_stuck',
180 self
.assert_valid_command(['pg', 'dump_stuck',
184 def one_pgid(self
, command
):
185 self
.assert_valid_command(['pg', command
, '1.1'])
186 assert_equal({}, validate_command(sigdict
, ['pg', command
]))
187 assert_equal({}, validate_command(sigdict
, ['pg', command
, '1']))
192 def test_scrub(self
):
193 self
.one_pgid('scrub')
195 def test_deep_scrub(self
):
196 self
.one_pgid('deep-scrub')
198 def test_repair(self
):
199 self
.one_pgid('repair')
201 def test_debug(self
):
202 self
.assert_valid_command(['pg',
204 'unfound_objects_exist'])
205 self
.assert_valid_command(['pg',
207 'degraded_pgs_exist'])
208 assert_equal({}, validate_command(sigdict
, ['pg', 'debug']))
209 assert_equal({}, validate_command(sigdict
, ['pg', 'debug',
212 def test_pg_missing_args_output(self
):
213 ret
, _
, stderr
= self
.capture_output(['pg'], stderr
=True)
214 assert_equal({}, ret
)
215 assert_regexp_matches(stderr
, re
.compile('no valid command found.* closest matches'))
217 def test_pg_wrong_arg_output(self
):
218 ret
, _
, stderr
= self
.capture_output(['pg', 'map', 'bad-pgid'],
220 assert_equal({}, ret
)
221 assert_in("Invalid command", stderr
)
224 class TestAuth(TestArgparse
):
226 def test_export(self
):
227 self
.assert_valid_command(['auth', 'export'])
228 self
.assert_valid_command(['auth',
231 assert_equal({}, validate_command(sigdict
, ['auth',
237 self
.check_1_string_arg('auth', 'get')
239 def test_get_key(self
):
240 self
.check_1_string_arg('auth', 'get-key')
242 def test_print_key(self
):
243 self
.check_1_string_arg('auth', 'print-key')
244 self
.check_1_string_arg('auth', 'print_key')
247 self
.check_no_arg('auth', 'list')
249 def test_import(self
):
250 self
.check_no_arg('auth', 'import')
253 self
.check_1_or_more_string_args('auth', 'add')
255 def test_get_or_create_key(self
):
256 self
.check_1_or_more_string_args('auth', 'get-or-create-key')
258 def test_get_or_create(self
):
259 self
.check_1_or_more_string_args('auth', 'get-or-create')
262 assert_equal({}, validate_command(sigdict
, ['auth',
264 assert_equal({}, validate_command(sigdict
, ['auth',
267 self
.assert_valid_command(['auth',
273 self
.check_1_string_arg('auth', 'del')
276 class TestMonitor(TestArgparse
):
278 def test_compact(self
):
279 self
.assert_valid_command(['compact'])
281 def test_scrub(self
):
282 self
.assert_valid_command(['scrub'])
285 self
.assert_valid_command(['fsid'])
288 assert_equal({}, validate_command(sigdict
, ['log']))
289 self
.assert_valid_command(['log', 'a logtext'])
290 self
.assert_valid_command(['log', 'a logtext', 'and another'])
292 def test_injectargs(self
):
293 assert_equal({}, validate_command(sigdict
, ['injectargs']))
294 self
.assert_valid_command(['injectargs', 'one'])
295 self
.assert_valid_command(['injectargs', 'one', 'two'])
297 def test_status(self
):
298 self
.assert_valid_command(['status'])
300 def test_health(self
):
301 self
.assert_valid_command(['health'])
302 self
.assert_valid_command(['health', 'detail'])
303 assert_equal({}, validate_command(sigdict
, ['health', 'invalid']))
304 assert_equal({}, validate_command(sigdict
, ['health', 'detail',
308 self
.assert_valid_command(['df'])
309 self
.assert_valid_command(['df', 'detail'])
310 assert_equal({}, validate_command(sigdict
, ['df', 'invalid']))
311 assert_equal({}, validate_command(sigdict
, ['df', 'detail',
314 def test_report(self
):
315 self
.assert_valid_command(['report'])
316 self
.assert_valid_command(['report', 'tag1'])
317 self
.assert_valid_command(['report', 'tag1', 'tag2'])
319 def test_quorum_status(self
):
320 self
.assert_valid_command(['quorum_status'])
323 assert_equal({}, validate_command(sigdict
, ['tell']))
324 assert_equal({}, validate_command(sigdict
, ['tell', 'invalid']))
325 for name
in ('osd', 'mon', 'client', 'mds'):
326 assert_equal({}, validate_command(sigdict
, ['tell', name
]))
327 assert_equal({}, validate_command(sigdict
, ['tell',
329 self
.assert_valid_command(['tell', name
+ ".42", 'something'])
330 self
.assert_valid_command(['tell', name
+ ".42",
335 class TestMDS(TestArgparse
):
338 self
.check_no_arg('mds', 'stat')
340 def test_compat_show(self
):
341 self
.assert_valid_command(['mds', 'compat', 'show'])
342 assert_equal({}, validate_command(sigdict
, ['mds', 'compat']))
343 assert_equal({}, validate_command(sigdict
, ['mds', 'compat',
346 def test_set_state(self
):
347 self
.assert_valid_command(['mds', 'set_state', '1', '2'])
348 assert_equal({}, validate_command(sigdict
, ['mds', 'set_state']))
349 assert_equal({}, validate_command(sigdict
, ['mds', 'set_state', '-1']))
350 assert_equal({}, validate_command(sigdict
, ['mds', 'set_state',
352 assert_equal({}, validate_command(sigdict
, ['mds', 'set_state',
356 self
.check_1_string_arg('mds', 'fail')
359 # Valid: single GID argument present
360 self
.assert_valid_command(['mds', 'rm', '1'])
362 # Missing GID arg: invalid
363 assert_equal({}, validate_command(sigdict
, ['mds', 'rm']))
365 assert_equal({}, validate_command(sigdict
, ['mds', 'rm', '1', 'mds.42']))
367 def test_rmfailed(self
):
368 self
.assert_valid_command(['mds', 'rmfailed', '0'])
369 self
.assert_valid_command(['mds', 'rmfailed', '0', '--yes-i-really-mean-it'])
370 assert_equal({}, validate_command(sigdict
, ['mds', 'rmfailed', '0',
371 '--yes-i-really-mean-it',
374 def test_compat_rm_compat(self
):
375 self
.assert_valid_command(['mds', 'compat', 'rm_compat', '1'])
376 assert_equal({}, validate_command(sigdict
, ['mds',
379 assert_equal({}, validate_command(sigdict
, ['mds',
382 assert_equal({}, validate_command(sigdict
, ['mds',
384 'rm_compat', '1', '1']))
386 def test_incompat_rm_incompat(self
):
387 self
.assert_valid_command(['mds', 'compat', 'rm_incompat', '1'])
388 assert_equal({}, validate_command(sigdict
, ['mds',
391 assert_equal({}, validate_command(sigdict
, ['mds',
393 'rm_incompat', '-1']))
394 assert_equal({}, validate_command(sigdict
, ['mds',
396 'rm_incompat', '1', '1']))
399 class TestFS(TestArgparse
):
402 self
.check_0_or_1_natural_arg('fs', 'dump')
404 def test_fs_new(self
):
405 self
.assert_valid_command(['fs', 'new', 'default', 'metadata', 'data'])
407 def test_fs_set_max_mds(self
):
408 self
.assert_valid_command(['fs', 'set', 'default', 'max_mds', '1'])
409 self
.assert_valid_command(['fs', 'set', 'default', 'max_mds', '2'])
411 def test_fs_set_cluster_down(self
):
412 self
.assert_valid_command(['fs', 'set', 'default', 'down', 'true'])
414 def test_fs_set_cluster_up(self
):
415 self
.assert_valid_command(['fs', 'set', 'default', 'down', 'false'])
417 def test_fs_set_cluster_joinable(self
):
418 self
.assert_valid_command(['fs', 'set', 'default', 'joinable', 'true'])
420 def test_fs_set_cluster_not_joinable(self
):
421 self
.assert_valid_command(['fs', 'set', 'default', 'joinable', 'false'])
423 def test_fs_set(self
):
424 self
.assert_valid_command(['fs', 'set', 'default', 'max_file_size', '2'])
425 self
.assert_valid_command(['fs', 'set', 'default', 'allow_new_snaps', 'no'])
426 assert_equal({}, validate_command(sigdict
, ['fs',
430 def test_fs_add_data_pool(self
):
431 self
.assert_valid_command(['fs', 'add_data_pool', 'default', '1'])
432 self
.assert_valid_command(['fs', 'add_data_pool', 'default', 'foo'])
434 def test_fs_remove_data_pool(self
):
435 self
.assert_valid_command(['fs', 'rm_data_pool', 'default', '1'])
436 self
.assert_valid_command(['fs', 'rm_data_pool', 'default', 'foo'])
438 def test_fs_rm(self
):
439 self
.assert_valid_command(['fs', 'rm', 'default'])
440 self
.assert_valid_command(['fs', 'rm', 'default', '--yes-i-really-mean-it'])
441 assert_equal({}, validate_command(sigdict
, ['fs', 'rm', 'default', '--yes-i-really-mean-it', 'toomany']))
443 def test_fs_ls(self
):
444 self
.assert_valid_command(['fs', 'ls'])
445 assert_equal({}, validate_command(sigdict
, ['fs', 'ls', 'toomany']))
447 def test_fs_set_default(self
):
448 self
.assert_valid_command(['fs', 'set-default', 'cephfs'])
449 assert_equal({}, validate_command(sigdict
, ['fs', 'set-default']))
450 assert_equal({}, validate_command(sigdict
, ['fs', 'set-default', 'cephfs', 'toomany']))
453 class TestMon(TestArgparse
):
456 self
.check_0_or_1_natural_arg('mon', 'dump')
459 self
.check_no_arg('mon', 'stat')
461 def test_getmap(self
):
462 self
.check_0_or_1_natural_arg('mon', 'getmap')
465 self
.assert_valid_command(['mon', 'add', 'name', '1.2.3.4:1234'])
466 assert_equal({}, validate_command(sigdict
, ['mon', 'add']))
467 assert_equal({}, validate_command(sigdict
, ['mon', 'add', 'name']))
468 assert_equal({}, validate_command(sigdict
, ['mon', 'add',
472 def test_remove(self
):
473 self
.assert_valid_command(['mon', 'remove', 'name'])
474 assert_equal({}, validate_command(sigdict
, ['mon', 'remove']))
475 assert_equal({}, validate_command(sigdict
, ['mon', 'remove',
479 class TestOSD(TestArgparse
):
482 self
.check_no_arg('osd', 'stat')
485 self
.check_0_or_1_natural_arg('osd', 'dump')
487 def test_osd_tree(self
):
488 self
.check_0_or_1_natural_arg('osd', 'tree')
490 def test_osd_ls(self
):
491 self
.check_0_or_1_natural_arg('osd', 'ls')
493 def test_osd_getmap(self
):
494 self
.check_0_or_1_natural_arg('osd', 'getmap')
496 def test_osd_getcrushmap(self
):
497 self
.check_0_or_1_natural_arg('osd', 'getcrushmap')
500 self
.check_no_arg('osd', 'perf')
502 def test_getmaxosd(self
):
503 self
.check_no_arg('osd', 'getmaxosd')
506 self
.check_1_natural_arg('osd', 'find')
509 self
.assert_valid_command(['osd', 'map', 'poolname', 'objectname'])
510 self
.assert_valid_command(['osd', 'map', 'poolname', 'objectname', 'nspace'])
511 assert_equal({}, validate_command(sigdict
, ['osd', 'map']))
512 assert_equal({}, validate_command(sigdict
, ['osd', 'map', 'poolname']))
513 assert_equal({}, validate_command(sigdict
, ['osd', 'map',
514 'poolname', 'objectname', 'nspace',
517 def test_metadata(self
):
518 self
.check_0_or_1_natural_arg('osd', 'metadata')
520 def test_scrub(self
):
521 self
.check_1_string_arg('osd', 'scrub')
523 def test_deep_scrub(self
):
524 self
.check_1_string_arg('osd', 'deep-scrub')
526 def test_repair(self
):
527 self
.check_1_string_arg('osd', 'repair')
529 def test_lspools(self
):
530 self
.assert_valid_command(['osd', 'lspools'])
531 assert_equal({}, validate_command(sigdict
, ['osd', 'lspools',
534 def test_blocklist_ls(self
):
535 self
.assert_valid_command(['osd', 'blocklist', 'ls'])
536 assert_equal({}, validate_command(sigdict
, ['osd', 'blocklist']))
537 assert_equal({}, validate_command(sigdict
, ['osd', 'blocklist',
540 def test_crush_rule(self
):
541 assert_equal({}, validate_command(sigdict
, ['osd', 'crush']))
542 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule']))
543 for subcommand
in ('list', 'ls'):
544 self
.assert_valid_command(['osd', 'crush', 'rule', subcommand
])
545 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
549 def test_crush_rule_dump(self
):
550 self
.assert_valid_command(['osd', 'crush', 'rule', 'dump'])
551 self
.assert_valid_command(['osd', 'crush', 'rule', 'dump', 'RULE'])
552 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
557 def test_crush_dump(self
):
558 self
.assert_valid_command(['osd', 'crush', 'dump'])
559 assert_equal({}, validate_command(sigdict
, ['osd', 'crush']))
560 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
564 def test_setcrushmap(self
):
565 self
.check_no_arg('osd', 'setcrushmap')
567 def test_crush_add_bucket(self
):
568 self
.assert_valid_command(['osd', 'crush', 'add-bucket',
570 self
.assert_valid_command(['osd', 'crush', 'add-bucket',
571 'name', 'type', 'root=foo-root', 'host=foo-host'])
572 assert_equal({}, validate_command(sigdict
, ['osd', 'crush']))
573 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
575 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
579 def test_crush_rename_bucket(self
):
580 self
.assert_valid_command(['osd', 'crush', 'rename-bucket',
581 'srcname', 'dstname'])
582 assert_equal({}, validate_command(sigdict
, ['osd', 'crush']))
583 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
585 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
588 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
589 'rename-bucket', 'srcname',
592 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
593 'rename-bucket', '^^^',
595 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
596 'rename-bucket', 'srcname',
599 def check_crush_setter(self
, setter
):
600 self
.assert_valid_command(['osd', 'crush', setter
,
601 '*', '2.3', 'AZaz09-_.='])
602 self
.assert_valid_command(['osd', 'crush', setter
,
603 'osd.0', '2.3', 'AZaz09-_.='])
604 self
.assert_valid_command(['osd', 'crush', setter
,
605 '0', '2.3', 'AZaz09-_.='])
606 self
.assert_valid_command(['osd', 'crush', setter
,
607 '0', '2.3', 'AZaz09-_.=', 'AZaz09-_.='])
608 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
611 ret
= validate_command(sigdict
, ['osd', 'crush',
615 assert ret
in [None, {}]
616 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
622 def test_crush_set(self
):
623 assert_equal({}, validate_command(sigdict
, ['osd', 'crush']))
624 self
.check_crush_setter('set')
626 def test_crush_add(self
):
627 assert_equal({}, validate_command(sigdict
, ['osd', 'crush']))
628 self
.check_crush_setter('add')
630 def test_crush_create_or_move(self
):
631 assert_equal({}, validate_command(sigdict
, ['osd', 'crush']))
632 self
.check_crush_setter('create-or-move')
634 def test_crush_move(self
):
635 self
.assert_valid_command(['osd', 'crush', 'move',
636 'AZaz09-_.', 'AZaz09-_.='])
637 self
.assert_valid_command(['osd', 'crush', 'move',
638 '0', 'AZaz09-_.=', 'AZaz09-_.='])
639 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
641 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
642 'move', 'AZaz09-_.']))
643 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
646 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
650 def test_crush_link(self
):
651 self
.assert_valid_command(['osd', 'crush', 'link',
652 'name', 'AZaz09-_.='])
653 self
.assert_valid_command(['osd', 'crush', 'link',
654 'name', 'AZaz09-_.=', 'AZaz09-_.='])
655 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
657 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
661 def test_crush_rm(self
):
662 for alias
in ('rm', 'remove', 'unlink'):
663 self
.assert_valid_command(['osd', 'crush', alias
, 'AZaz09-_.'])
664 self
.assert_valid_command(['osd', 'crush', alias
,
665 'AZaz09-_.', 'AZaz09-_.'])
666 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
668 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
674 def test_crush_reweight(self
):
675 self
.assert_valid_command(['osd', 'crush', 'reweight',
677 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
679 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
682 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
686 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
691 def test_crush_tunables(self
):
692 for tunable
in ('legacy', 'argonaut', 'bobtail', 'firefly',
693 'optimal', 'default'):
694 self
.assert_valid_command(['osd', 'crush', 'tunables',
696 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
698 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
700 'default', 'toomany']))
702 def test_crush_rule_create_simple(self
):
703 self
.assert_valid_command(['osd', 'crush', 'rule', 'create-simple',
704 'AZaz09-_.', 'AZaz09-_.', 'AZaz09-_.'])
705 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule',
707 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule',
710 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule',
714 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule',
719 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule',
724 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule',
729 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule',
736 def test_crush_rule_create_erasure(self
):
737 self
.assert_valid_command(['osd', 'crush', 'rule', 'create-erasure',
739 self
.assert_valid_command(['osd', 'crush', 'rule', 'create-erasure',
740 'AZaz09-_.', 'whatever'])
741 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule',
743 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule',
746 assert_equal({}, validate_command(sigdict
, ['osd', 'crush', 'rule',
750 def test_crush_rule_rm(self
):
751 self
.assert_valid_command(['osd', 'crush', 'rule', 'rm', 'AZaz09-_.'])
752 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
754 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
757 assert_equal({}, validate_command(sigdict
, ['osd', 'crush',
762 def test_setmaxosd(self
):
763 self
.check_1_natural_arg('osd', 'setmaxosd')
765 def test_pause(self
):
766 self
.check_no_arg('osd', 'pause')
768 def test_unpause(self
):
769 self
.check_no_arg('osd', 'unpause')
771 def test_erasure_code_profile_set(self
):
772 self
.assert_valid_command(['osd', 'erasure-code-profile', 'set',
774 self
.assert_valid_command(['osd', 'erasure-code-profile', 'set',
776 self
.assert_valid_command(['osd', 'erasure-code-profile', 'set',
777 'name', 'A=B', 'C=D'])
778 assert_equal({}, validate_command(sigdict
, ['osd',
779 'erasure-code-profile',
781 assert_equal({}, validate_command(sigdict
, ['osd',
782 'erasure-code-profile',
786 def test_erasure_code_profile_get(self
):
787 self
.assert_valid_command(['osd', 'erasure-code-profile', 'get',
789 assert_equal({}, validate_command(sigdict
, ['osd',
790 'erasure-code-profile',
792 assert_equal({}, validate_command(sigdict
, ['osd',
793 'erasure-code-profile',
797 def test_erasure_code_profile_rm(self
):
798 self
.assert_valid_command(['osd', 'erasure-code-profile', 'rm',
800 assert_equal({}, validate_command(sigdict
, ['osd',
801 'erasure-code-profile',
803 assert_equal({}, validate_command(sigdict
, ['osd',
804 'erasure-code-profile',
808 def test_erasure_code_profile_ls(self
):
809 self
.assert_valid_command(['osd', 'erasure-code-profile', 'ls'])
810 assert_equal({}, validate_command(sigdict
, ['osd',
811 'erasure-code-profile',
815 def test_set_unset(self
):
816 for action
in ('set', 'unset'):
817 for flag
in ('pause', 'noup', 'nodown', 'noout', 'noin',
818 'nobackfill', 'norecover', 'noscrub', 'nodeep-scrub'):
819 self
.assert_valid_command(['osd', action
, flag
])
820 assert_equal({}, validate_command(sigdict
, ['osd', action
]))
821 assert_equal({}, validate_command(sigdict
, ['osd', action
,
823 assert_equal({}, validate_command(sigdict
, ['osd', action
,
824 'pause', 'toomany']))
827 self
.check_1_or_more_string_args('osd', 'down')
830 self
.check_1_or_more_string_args('osd', 'out')
833 self
.check_1_or_more_string_args('osd', 'in')
836 self
.check_1_or_more_string_args('osd', 'rm')
838 def test_reweight(self
):
839 self
.assert_valid_command(['osd', 'reweight', '1', '0.1'])
840 assert_equal({}, validate_command(sigdict
, ['osd', 'reweight']))
841 assert_equal({}, validate_command(sigdict
, ['osd', 'reweight',
843 assert_equal({}, validate_command(sigdict
, ['osd', 'reweight',
845 assert_equal({}, validate_command(sigdict
, ['osd', 'reweight',
847 assert_equal({}, validate_command(sigdict
, ['osd', 'reweight',
852 self
.assert_valid_command(['osd', 'lost', '1',
853 '--yes-i-really-mean-it'])
854 self
.assert_valid_command(['osd', 'lost', '1'])
855 assert_equal({}, validate_command(sigdict
, ['osd', 'lost']))
856 assert_equal({}, validate_command(sigdict
, ['osd', 'lost',
859 assert_equal({}, validate_command(sigdict
, ['osd', 'lost',
861 '--yes-i-really-mean-it']))
862 assert_equal({}, validate_command(sigdict
, ['osd', 'lost',
864 '--yes-i-really-mean-it',
867 def test_create(self
):
868 uuid
= '12345678123456781234567812345678'
869 self
.assert_valid_command(['osd', 'create'])
870 self
.assert_valid_command(['osd', 'create',
872 assert_equal({}, validate_command(sigdict
, ['osd', 'create',
874 assert_equal({}, validate_command(sigdict
, ['osd', 'create',
878 def test_blocklist(self
):
879 for action
in ('add', 'rm'):
880 self
.assert_valid_command(['osd', 'blocklist', action
,
882 self
.assert_valid_command(['osd', 'blocklist', action
,
884 self
.assert_valid_command(['osd', 'blocklist', action
,
885 '1.2.3.4/567', '600.40'])
886 self
.assert_valid_command(['osd', 'blocklist', action
,
887 '1.2.3.4', '600.40'])
888 assert_equal({}, validate_command(sigdict
, ['osd', 'blocklist',
892 assert_equal({}, validate_command(sigdict
, ['osd', 'blocklist',
896 assert_equal({}, validate_command(sigdict
, ['osd', 'blocklist',
902 def test_pool_mksnap(self
):
903 self
.assert_valid_command(['osd', 'pool', 'mksnap',
904 'poolname', 'snapname'])
905 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'mksnap']))
906 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'mksnap',
908 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'mksnap',
909 'poolname', 'snapname',
912 def test_pool_rmsnap(self
):
913 self
.assert_valid_command(['osd', 'pool', 'rmsnap',
914 'poolname', 'snapname'])
915 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'rmsnap']))
916 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'rmsnap',
918 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'rmsnap',
919 'poolname', 'snapname',
922 def test_pool_kwargs(self
):
924 Use the pool creation command to exercise keyword-style arguments
925 since it has lots of parameters
927 # Simply use a keyword arg instead of a positional arg, in its
928 # normal order (pgp_num after pg_num)
931 "prefix": "osd pool create",
935 }, validate_command(sigdict
, [
936 'osd', 'pool', 'create', "foo", "8", "--pgp_num", "16"]))
938 # Again, but using the "--foo=bar" style
941 "prefix": "osd pool create",
945 }, validate_command(sigdict
, [
946 'osd', 'pool', 'create', "foo", "8", "--pgp_num=16"]))
948 # Specify keyword args in a different order than their definitions
949 # (pgp_num after pool_type)
952 "prefix": "osd pool create",
956 "pool_type": "replicated"
957 }, validate_command(sigdict
, [
958 'osd', 'pool', 'create', "foo", "8",
959 "--pool_type", "replicated",
962 # Use a keyword argument that doesn't exist, should fail validation
963 assert_equal({}, validate_command(sigdict
,
964 ['osd', 'pool', 'create', "foo", "8", "--foo=bar"]))
967 # Long form of a boolean argument (--foo=true)
970 "prefix": "osd pool delete",
973 "yes_i_really_really_mean_it": True
974 }, validate_command(sigdict
, [
975 'osd', 'pool', 'delete', "foo", "foo",
976 "--yes-i-really-really-mean-it=true"]))
978 def test_pool_bool_args(self
):
980 Use pool deletion to exercise boolean arguments since it has
981 the --yes-i-really-really-mean-it flags
984 # Short form of a boolean argument (--foo)
987 "prefix": "osd pool delete",
990 "yes_i_really_really_mean_it": True
991 }, validate_command(sigdict
, [
992 'osd', 'pool', 'delete', "foo", "foo",
993 "--yes-i-really-really-mean-it"]))
995 # Long form of a boolean argument (--foo=true)
998 "prefix": "osd pool delete",
1001 "yes_i_really_really_mean_it": True
1002 }, validate_command(sigdict
, [
1003 'osd', 'pool', 'delete', "foo", "foo",
1004 "--yes-i-really-really-mean-it=true"]))
1006 # Negative form of a boolean argument (--foo=false)
1009 "prefix": "osd pool delete",
1012 "yes_i_really_really_mean_it": False
1013 }, validate_command(sigdict
, [
1014 'osd', 'pool', 'delete', "foo", "foo",
1015 "--yes-i-really-really-mean-it=false"]))
1017 # Invalid value boolean argument (--foo=somethingelse)
1018 assert_equal({}, validate_command(sigdict
, [
1019 'osd', 'pool', 'delete', "foo", "foo",
1020 "--yes-i-really-really-mean-it=rhubarb"]))
1022 def test_pool_create(self
):
1023 self
.assert_valid_command(['osd', 'pool', 'create',
1025 self
.assert_valid_command(['osd', 'pool', 'create',
1026 'poolname', '128', '128'])
1027 self
.assert_valid_command(['osd', 'pool', 'create',
1028 'poolname', '128', '128',
1030 self
.assert_valid_command(['osd', 'pool', 'create',
1031 'poolname', '128', '128',
1032 'erasure', 'A-Za-z0-9-_.', 'ruleset^^'])
1033 self
.assert_valid_command(['osd', 'pool', 'create', 'poolname'])
1034 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'create']))
1035 # invalid pg_num and pgp_num, like "-1", could spill over to
1036 # erasure_code_profile and rule as they are valid profile and rule
1037 # names, so validate_commands() cannot identify such cases.
1038 # but if they are matched by profile and rule, the "rule" argument
1039 # won't get a chance to be matched anymore.
1040 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'create',
1044 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'create',
1049 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'create',
1052 'erasure', 'profile',
1055 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'create',
1058 'INVALID', 'profile',
1061 def test_pool_delete(self
):
1062 self
.assert_valid_command(['osd', 'pool', 'delete',
1063 'poolname', 'poolname',
1064 '--yes-i-really-really-mean-it'])
1065 self
.assert_valid_command(['osd', 'pool', 'delete',
1066 'poolname', 'poolname'])
1067 self
.assert_valid_command(['osd', 'pool', 'delete',
1069 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'delete']))
1070 assert_equal({}, validate_command(sigdict
,
1071 ['osd', 'pool', 'delete',
1072 'poolname', 'poolname',
1073 '--yes-i-really-really-mean-it',
1076 def test_pool_rename(self
):
1077 self
.assert_valid_command(['osd', 'pool', 'rename',
1078 'poolname', 'othername'])
1079 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'rename']))
1080 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'rename',
1082 assert_equal({}, validate_command(sigdict
, ['osd', 'pool', 'rename',
1083 'poolname', 'othername',
1086 def test_pool_get(self
):
1087 for var
in ('size', 'min_size',
1088 'pg_num', 'pgp_num', 'crush_rule', 'fast_read',
1089 'scrub_min_interval', 'scrub_max_interval',
1090 'deep_scrub_interval', 'recovery_priority',
1091 'recovery_op_priority'):
1092 self
.assert_valid_command(['osd', 'pool', 'get', 'poolname', var
])
1093 assert_equal({}, validate_command(sigdict
, ['osd', 'pool']))
1094 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1096 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1097 'get', 'poolname']))
1098 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1100 'size', 'toomany']))
1101 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1105 def test_pool_set(self
):
1106 for var
in ('size', 'min_size',
1107 'pg_num', 'pgp_num', 'crush_rule',
1108 'hashpspool', 'fast_read',
1109 'scrub_min_interval', 'scrub_max_interval',
1110 'deep_scrub_interval', 'recovery_priority',
1111 'recovery_op_priority'):
1112 self
.assert_valid_command(['osd', 'pool',
1113 'set', 'poolname', var
, 'value'])
1114 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1116 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1117 'set', 'poolname']))
1118 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1123 def test_pool_set_quota(self
):
1124 for field
in ('max_objects', 'max_bytes'):
1125 self
.assert_valid_command(['osd', 'pool', 'set-quota',
1126 'poolname', field
, '10K'])
1127 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1129 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1132 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1136 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1141 assert_equal({}, validate_command(sigdict
, ['osd', 'pool',
1148 def test_reweight_by_utilization(self
):
1149 self
.assert_valid_command(['osd', 'reweight-by-utilization'])
1150 self
.assert_valid_command(['osd', 'reweight-by-utilization', '100'])
1151 self
.assert_valid_command(['osd', 'reweight-by-utilization', '100', '.1'])
1152 assert_equal({}, validate_command(sigdict
, ['osd',
1153 'reweight-by-utilization',
1157 def test_tier_op(self
):
1158 for op
in ('add', 'remove', 'set-overlay'):
1159 self
.assert_valid_command(['osd', 'tier', op
,
1160 'poolname', 'othername'])
1161 assert_equal({}, validate_command(sigdict
, ['osd', 'tier', op
]))
1162 assert_equal({}, validate_command(sigdict
, ['osd', 'tier', op
,
1164 assert_equal({}, validate_command(sigdict
, ['osd', 'tier', op
,
1169 def test_tier_cache_mode(self
):
1170 for mode
in ('none', 'writeback', 'forward', 'readonly', 'readforward', 'readproxy'):
1171 self
.assert_valid_command(['osd', 'tier', 'cache-mode',
1173 assert_equal({}, validate_command(sigdict
, ['osd', 'tier',
1175 assert_equal({}, validate_command(sigdict
, ['osd', 'tier',
1179 def test_tier_remove_overlay(self
):
1180 self
.assert_valid_command(['osd', 'tier', 'remove-overlay',
1182 assert_equal({}, validate_command(sigdict
, ['osd', 'tier',
1184 assert_equal({}, validate_command(sigdict
, ['osd', 'tier',
1189 def set_ratio(self
, command
):
1190 self
.assert_valid_command(['osd',
1193 assert_equal({}, validate_command(sigdict
, ['osd', command
]))
1194 assert_equal({}, validate_command(sigdict
, ['osd',
1198 def test_set_full_ratio(self
):
1199 self
.set_ratio('set-full-ratio')
1201 def test_set_backfillfull_ratio(self
):
1202 self
.set_ratio('set-backfillfull-ratio')
1204 def test_set_nearfull_ratio(self
):
1205 self
.set_ratio('set-nearfull-ratio')
1208 class TestConfigKey(TestArgparse
):
1211 self
.check_1_string_arg('config-key', 'get')
1214 self
.assert_valid_command(['config-key', 'put',
1216 self
.assert_valid_command(['config-key', 'put',
1218 assert_equal({}, validate_command(sigdict
, ['config-key', 'put']))
1219 assert_equal({}, validate_command(sigdict
, ['config-key', 'put',
1224 self
.check_1_string_arg('config-key', 'del')
1226 def test_exists(self
):
1227 self
.check_1_string_arg('config-key', 'exists')
1229 def test_dump(self
):
1230 self
.check_0_or_1_string_arg('config-key', 'dump')
1232 def test_list(self
):
1233 self
.check_no_arg('config-key', 'list')
1236 class TestValidate(TestCase
):
1244 self
.prefix
= ['some', 'random', 'cmd']
1246 {'name': 'variable_one', 'type': 'CephString'},
1247 {'name': 'variable_two', 'type': 'CephString'},
1248 {'name': 'variable_three', 'type': 'CephString'},
1249 {'name': 'variable_four', 'type': 'CephInt'},
1250 {'name': 'variable_five', 'type': 'CephString'}]
1252 for d
in self
.args_dict
:
1253 if d
['type'] == 'CephInt':
1254 val
= "{}".format(random
.randint(0, 100))
1255 elif d
['type'] == 'CephString':
1256 letters
= string
.ascii_letters
1257 str_len
= random
.randint(5, 10)
1258 val
= ''.join(random
.choice(letters
) for _
in range(str_len
))
1262 self
.args
.append((d
['name'], val
))
1264 self
.sig
= parse_funcsig(self
.prefix
+ self
.args_dict
)
1266 def arg_kwarg_test(self
, prefix
, args
, sig
, arg_type
=0):
1268 Runs validate in different arg/kargs ways.
1270 :param prefix: List of prefix commands (that can't be kwarged)
1271 :param args: a list of kwarg, arg pairs: [(k1, v1), (k2, v2), ...]
1272 :param sig: The sig to match
1273 :param arg_type: how to build the args to send. As positional args (ARGS),
1274 as long kwargs (KWARGS [--k v]), other style long kwargs
1275 (KWARGS_EQ (--k=v]), and mixed (MIXED) where there will be
1276 a random mix of the above.
1277 :return: None, the method will assert.
1279 final_args
= list(prefix
)
1282 if a_type
== self
.MIXED
:
1283 a_type
= random
.choice((self
.ARGS
,
1286 if a_type
== self
.ARGS
:
1287 final_args
.append(v
)
1288 elif a_type
== self
.KWARGS
:
1289 final_args
.extend(["--{}".format(k
), v
])
1291 final_args
.append("--{}={}".format(k
, v
))
1294 validate(final_args
, sig
)
1295 except (ArgumentError
, ArgumentMissing
,
1296 ArgumentNumber
, ArgumentTooFew
, ArgumentValid
) as ex
:
1297 self
.fail("Validation failed: {}".format(str(ex
)))
1299 def test_args_and_kwargs_validate(self
):
1300 for arg_type
in (self
.ARGS
, self
.KWARGS
, self
.KWARGS_EQ
, self
.MIXED
):
1301 self
.arg_kwarg_test(self
.prefix
, self
.args
, self
.sig
, arg_type
)
1304 # compile-command: "cd ../../..; cmake --build build --target get_command_descriptions -j4 &&
1305 # CEPH_BIN=build/bin \
1306 # PYTHONPATH=src/pybind nosetests --stop \
1307 # src/test/pybind/test_ceph_argparse.py:TestOSD.test_rm"