122
122
help="Select all clients")
123
123
parser.add_argument("-v", "--verbose", action="store_true",
124
124
help="Print all fields")
125
parser.add_argument("-j", "--dump-json", action="store_true",
125
parser.add_argument("-j", "--dump-json", dest="commands",
126
action="append_const", default=[],
127
const=command.DumpJSON(),
126
128
help="Dump client data in JSON format")
127
129
enable_disable = parser.add_mutually_exclusive_group()
128
enable_disable.add_argument("-e", "--enable", action="store_true",
130
enable_disable.add_argument("-e", "--enable", dest="commands",
131
action="append_const", default=[],
132
const=command.Enable(),
129
133
help="Enable client")
130
enable_disable.add_argument("-d", "--disable",
134
enable_disable.add_argument("-d", "--disable", dest="commands",
135
action="append_const", default=[],
136
const=command.Disable(),
132
137
help="disable client")
133
parser.add_argument("-b", "--bump-timeout", action="store_true",
138
parser.add_argument("-b", "--bump-timeout", dest="commands",
139
action="append_const", default=[],
140
const=command.BumpTimeout(),
134
141
help="Bump timeout for client")
135
142
start_stop_checker = parser.add_mutually_exclusive_group()
136
143
start_stop_checker.add_argument("--start-checker",
145
action="append_const", default=[],
146
const=command.StartChecker(),
138
147
help="Start checker for client")
139
start_stop_checker.add_argument("--stop-checker",
148
start_stop_checker.add_argument("--stop-checker", dest="commands",
149
action="append_const", default=[],
150
const=command.StopChecker(),
141
151
help="Stop checker for client")
142
parser.add_argument("-V", "--is-enabled", action="store_true",
152
parser.add_argument("-V", "--is-enabled", dest="commands",
153
action="append_const", default=[],
154
const=command.IsEnabled(),
143
155
help="Check if client is enabled")
144
parser.add_argument("-r", "--remove", action="store_true",
156
parser.add_argument("-r", "--remove", dest="commands",
157
action="append_const", default=[],
158
const=command.Remove(),
145
159
help="Remove client")
146
parser.add_argument("-c", "--checker",
160
parser.add_argument("-c", "--checker", dest="commands",
161
action="append", default=[],
162
metavar="COMMAND", type=command.SetChecker,
147
163
help="Set checker command for client")
148
parser.add_argument("-t", "--timeout", type=string_to_delta,
149
help="Set timeout for client")
150
parser.add_argument("--extended-timeout", type=string_to_delta,
151
help="Set extended timeout for client")
152
parser.add_argument("-i", "--interval", type=string_to_delta,
153
help="Set checker interval for client")
165
"-t", "--timeout", dest="commands", action="append",
166
default=[], metavar="TIME",
167
type=command.SetTimeout.argparse(string_to_delta),
168
help="Set timeout for client")
170
"--extended-timeout", dest="commands", action="append",
171
default=[], metavar="TIME",
172
type=command.SetExtendedTimeout.argparse(string_to_delta),
173
help="Set extended timeout for client")
175
"-i", "--interval", dest="commands", action="append",
176
default=[], metavar="TIME",
177
type=command.SetInterval.argparse(string_to_delta),
178
help="Set checker interval for client")
154
179
approve_deny_default = parser.add_mutually_exclusive_group()
155
180
approve_deny_default.add_argument(
156
"--approve-by-default", action="store_true",
157
default=None, dest="approved_by_default",
181
"--approve-by-default", dest="commands",
182
action="append_const", default=[],
183
const=command.ApproveByDefault(),
158
184
help="Set client to be approved by default")
159
185
approve_deny_default.add_argument(
160
"--deny-by-default", action="store_false",
161
dest="approved_by_default",
186
"--deny-by-default", dest="commands",
187
action="append_const", default=[],
188
const=command.DenyByDefault(),
162
189
help="Set client to be denied by default")
163
parser.add_argument("--approval-delay", type=string_to_delta,
164
help="Set delay before client approve/deny")
165
parser.add_argument("--approval-duration", type=string_to_delta,
166
help="Set duration of one client approval")
167
parser.add_argument("-H", "--host", help="Set host for client")
168
parser.add_argument("-s", "--secret",
169
type=argparse.FileType(mode="rb"),
170
help="Set password blob (file) for client")
191
"--approval-delay", dest="commands", action="append",
192
default=[], metavar="TIME",
193
type=command.SetApprovalDelay.argparse(string_to_delta),
194
help="Set delay before client approve/deny")
196
"--approval-duration", dest="commands", action="append",
197
default=[], metavar="TIME",
198
type=command.SetApprovalDuration.argparse(string_to_delta),
199
help="Set duration of one client approval")
200
parser.add_argument("-H", "--host", dest="commands",
201
action="append", default=[], metavar="STRING",
202
type=command.SetHost,
203
help="Set host for client")
205
"-s", "--secret", dest="commands", action="append",
206
default=[], metavar="FILENAME",
207
type=command.SetSecret.argparse(argparse.FileType(mode="rb")),
208
help="Set password blob (file) for client")
171
209
approve_deny = parser.add_mutually_exclusive_group()
172
210
approve_deny.add_argument(
173
"-A", "--approve", action="store_true",
211
"-A", "--approve", dest="commands", action="append_const",
212
default=[], const=command.Approve(),
174
213
help="Approve any current client request")
175
approve_deny.add_argument("-D", "--deny", action="store_true",
214
approve_deny.add_argument("-D", "--deny", dest="commands",
215
action="append_const", default=[],
216
const=command.Deny(),
176
217
help="Deny any current client request")
177
218
parser.add_argument("--debug", action="store_true",
178
219
help="Debug mode (show D-Bus commands)")
369
410
"""Apply additional restrictions on options, not expressible in
372
def has_actions(options):
373
return any((options.enable,
375
options.bump_timeout,
376
options.start_checker,
377
options.stop_checker,
380
options.checker is not None,
381
options.timeout is not None,
382
options.extended_timeout is not None,
383
options.interval is not None,
384
options.approved_by_default is not None,
385
options.approval_delay is not None,
386
options.approval_duration is not None,
387
options.host is not None,
388
options.secret is not None,
413
def has_commands(options, commands=None):
415
commands = (command.Enable,
418
command.StartChecker,
424
command.SetExtendedTimeout,
426
command.ApproveByDefault,
427
command.DenyByDefault,
428
command.SetApprovalDelay,
429
command.SetApprovalDuration,
434
return any(isinstance(cmd, commands)
435
for cmd in options.commands)
392
if has_actions(options) and not (options.client or options.all):
437
if has_commands(options) and not (options.client or options.all):
393
438
parser.error("Options require clients names or --all.")
394
if options.verbose and has_actions(options):
439
if options.verbose and has_commands(options):
395
440
parser.error("--verbose can only be used alone.")
396
if options.dump_json and (options.verbose
397
or has_actions(options)):
441
if (has_commands(options, (command.DumpJSON,))
442
and (options.verbose or len(options.commands) > 1)):
398
443
parser.error("--dump-json can only be used alone.")
399
if options.all and not has_actions(options):
444
if options.all and not has_commands(options):
400
445
parser.error("--all requires an action.")
401
if options.is_enabled and len(options.client) > 1:
446
if (has_commands(options, (command.IsEnabled,))
447
and len(options.client) > 1):
402
448
parser.error("--is-enabled requires exactly one client")
404
options.remove = False
405
if has_actions(options) and not options.deny:
406
parser.error("--remove can only be combined with --deny")
407
options.remove = True
449
if (len(options.commands) > 1
450
and has_commands(options, (command.Remove,))
451
and not has_commands(options, (command.Deny,))):
452
parser.error("--remove can only be combined with --deny")
411
455
class dbus(object):
552
596
def commands_from_options(options):
556
if options.is_enabled:
557
commands.append(command.IsEnabled())
560
commands.append(command.Approve())
563
commands.append(command.Deny())
566
commands.append(command.Remove())
568
if options.dump_json:
569
commands.append(command.DumpJSON())
572
commands.append(command.Enable())
575
commands.append(command.Disable())
577
if options.bump_timeout:
578
commands.append(command.BumpTimeout())
580
if options.start_checker:
581
commands.append(command.StartChecker())
583
if options.stop_checker:
584
commands.append(command.StopChecker())
586
if options.approved_by_default is not None:
587
if options.approved_by_default:
588
commands.append(command.ApproveByDefault())
598
commands = list(options.commands)
600
def find_cmd(cmd, commands):
602
for i, c in enumerate(commands):
603
if isinstance(c, cmd):
607
# If command.Remove is present, move any instances of command.Deny
608
# to occur ahead of command.Remove.
609
index_of_remove = find_cmd(command.Remove, commands)
610
before_remove = commands[:index_of_remove]
611
after_remove = commands[index_of_remove:]
613
for cmd in after_remove:
614
if isinstance(cmd, command.Deny):
615
before_remove.append(cmd)
590
commands.append(command.DenyByDefault())
592
if options.checker is not None:
593
commands.append(command.SetChecker(options.checker))
595
if options.host is not None:
596
commands.append(command.SetHost(options.host))
598
if options.secret is not None:
599
commands.append(command.SetSecret(options.secret))
601
if options.timeout is not None:
602
commands.append(command.SetTimeout(options.timeout))
604
if options.extended_timeout:
606
command.SetExtendedTimeout(options.extended_timeout))
608
if options.interval is not None:
609
commands.append(command.SetInterval(options.interval))
611
if options.approval_delay is not None:
613
command.SetApprovalDelay(options.approval_delay))
615
if options.approval_duration is not None:
617
command.SetApprovalDuration(options.approval_duration))
617
cleaned_after.append(cmd)
618
if cleaned_after != after_remove:
619
commands = before_remove + cleaned_after
619
621
# If no command option has been given, show table of clients,
620
622
# optionally verbosely
967
974
def test_actions_requires_client_or_all(self):
968
975
for action, value in self.actions.items():
969
options = self.parser.parse_args()
970
setattr(options, action, value)
976
args = self.actionargs(action, value)
971
977
with self.assertParseError():
972
self.check_option_syntax(options)
978
self.parse_args(args)
974
# This mostly corresponds to the definition from has_actions() in
980
# This mostly corresponds to the definition from has_commands() in
975
981
# check_option_syntax()
977
# The actual values set here are not that important, but we do
978
# at least stick to the correct types, even though they are
982
"bump_timeout": True,
983
"start_checker": True,
984
"stop_checker": True,
988
"timeout": datetime.timedelta(),
989
"extended_timeout": datetime.timedelta(),
990
"interval": datetime.timedelta(),
991
"approved_by_default": True,
992
"approval_delay": datetime.timedelta(),
993
"approval_duration": datetime.timedelta(),
995
"secret": io.BytesIO(b"x"),
985
"--bump-timeout": None,
986
"--start-checker": None,
987
"--stop-checker": None,
988
"--is-enabled": None,
992
"--extended-timeout": "PT0S",
993
"--interval": "PT0S",
994
"--approve-by-default": None,
995
"--deny-by-default": None,
996
"--approval-delay": "PT0S",
997
"--approval-duration": "PT0S",
998
"--host": "hostname",
999
"--secret": "/dev/null",
1005
def actionargs(action, value, *args):
1006
if value is not None:
1007
return [action, value] + list(args)
1009
return [action] + list(args)
1000
1011
@contextlib.contextmanager
1001
1012
def assertParseError(self):
1002
1013
with self.assertRaises(SystemExit) as e:
1024
1039
def test_actions_all_conflicts_with_verbose(self):
1025
1040
for action, value in self.actions.items():
1026
options = self.parser.parse_args()
1027
setattr(options, action, value)
1029
options.verbose = True
1041
args = self.actionargs(action, value, "--all",
1030
1043
with self.assertParseError():
1031
self.check_option_syntax(options)
1044
self.parse_args(args)
1033
1046
def test_actions_with_client_conflicts_with_verbose(self):
1034
1047
for action, value in self.actions.items():
1035
options = self.parser.parse_args()
1036
setattr(options, action, value)
1037
options.verbose = True
1038
options.client = ["client"]
1048
args = self.actionargs(action, value, "--verbose",
1039
1050
with self.assertParseError():
1040
self.check_option_syntax(options)
1051
self.parse_args(args)
1042
1053
def test_dump_json_conflicts_with_verbose(self):
1043
options = self.parser.parse_args()
1044
options.dump_json = True
1045
options.verbose = True
1054
args = ["--dump-json", "--verbose"]
1046
1055
with self.assertParseError():
1047
self.check_option_syntax(options)
1056
self.parse_args(args)
1049
1058
def test_dump_json_conflicts_with_action(self):
1050
1059
for action, value in self.actions.items():
1051
options = self.parser.parse_args()
1052
setattr(options, action, value)
1053
options.dump_json = True
1060
args = self.actionargs(action, value, "--dump-json")
1054
1061
with self.assertParseError():
1055
self.check_option_syntax(options)
1062
self.parse_args(args)
1057
1064
def test_all_can_not_be_alone(self):
1058
options = self.parser.parse_args()
1060
1066
with self.assertParseError():
1061
self.check_option_syntax(options)
1067
self.parse_args(args)
1063
1069
def test_all_is_ok_with_any_action(self):
1064
1070
for action, value in self.actions.items():
1065
options = self.parser.parse_args()
1066
setattr(options, action, value)
1068
self.check_option_syntax(options)
1071
args = self.actionargs(action, value, "--all")
1072
self.parse_args(args)
1070
1074
def test_any_action_is_ok_with_one_client(self):
1071
1075
for action, value in self.actions.items():
1072
options = self.parser.parse_args()
1073
setattr(options, action, value)
1074
options.client = ["client"]
1075
self.check_option_syntax(options)
1076
args = self.actionargs(action, value, "client")
1077
self.parse_args(args)
1077
1079
def test_one_client_with_all_actions_except_is_enabled(self):
1078
options = self.parser.parse_args()
1079
1080
for action, value in self.actions.items():
1080
if action == "is_enabled":
1081
if action == "--is-enabled":
1082
setattr(options, action, value)
1083
options.client = ["client"]
1084
self.check_option_syntax(options)
1083
args = self.actionargs(action, value, "client")
1084
self.parse_args(args)
1086
1086
def test_two_clients_with_all_actions_except_is_enabled(self):
1087
options = self.parser.parse_args()
1088
1087
for action, value in self.actions.items():
1089
if action == "is_enabled":
1088
if action == "--is-enabled":
1091
setattr(options, action, value)
1092
options.client = ["client1", "client2"]
1093
self.check_option_syntax(options)
1090
args = self.actionargs(action, value, "client1",
1092
self.parse_args(args)
1095
1094
def test_two_clients_are_ok_with_actions_except_is_enabled(self):
1096
1095
for action, value in self.actions.items():
1097
if action == "is_enabled":
1096
if action == "--is-enabled":
1099
options = self.parser.parse_args()
1100
setattr(options, action, value)
1101
options.client = ["client1", "client2"]
1102
self.check_option_syntax(options)
1098
args = self.actionargs(action, value, "client1",
1100
self.parse_args(args)
1104
1102
def test_is_enabled_fails_without_client(self):
1105
options = self.parser.parse_args()
1106
options.is_enabled = True
1103
args = ["--is-enabled"]
1107
1104
with self.assertParseError():
1108
self.check_option_syntax(options)
1105
self.parse_args(args)
1110
1107
def test_is_enabled_fails_with_two_clients(self):
1111
options = self.parser.parse_args()
1112
options.is_enabled = True
1113
options.client = ["client1", "client2"]
1108
args = ["--is-enabled", "client1", "client2"]
1114
1109
with self.assertParseError():
1115
self.check_option_syntax(options)
1110
self.parse_args(args)
1117
1112
def test_remove_can_only_be_combined_with_action_deny(self):
1118
1113
for action, value in self.actions.items():
1119
if action in {"remove", "deny"}:
1114
if action in {"--remove", "--deny"}:
1121
options = self.parser.parse_args()
1122
setattr(options, action, value)
1124
options.remove = True
1116
args = self.actionargs(action, value, "--all",
1125
1118
with self.assertParseError():
1126
self.check_option_syntax(options)
1119
self.parse_args(args)
1129
1122
class Test_dbus_exceptions(unittest.TestCase):