-
-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathqubesctl
executable file
·132 lines (119 loc) · 5.49 KB
/
qubesctl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/python3
"""
Directly call a salt command in the modules, does not require a running salt
minion to run.
"""
from __future__ import print_function
import argparse
import sys
import subprocess
import qubessalt
import qubesadmin
import qubesadmin.vm
from salt.utils import context as ctx
from salt.runners import saltutil
def main(args=None): # pylint: disable=missing-docstring
parser = argparse.ArgumentParser()
parser.add_argument('--show-output', action='store_true',
help='Show output of management commands')
parser.add_argument('--force-color', action='store_true',
help='Force color output, allow control characters '
'from VM, UNSAFE')
parser.add_argument('--skip-dom0', action='store_true',
help='Skip dom0 configuration (VM creation etc)')
parser.add_argument('--max-concurrency', action='store',
help='Maximum number of VMs configured simultaneously '
'(default: %(default)d)',
type=int, default=4)
parser.add_argument('--skip-top-check', action='store_true',
help='Do not skip targeted qubes during a highstate if '
'it appears they are not targeted by any state')
parser.add_argument('--sync-extmods', action='store_true',
help='Sync *all* custom extension module types before '
'running the command to ensure they will be '
'available on the salt-ssh master')
group = parser.add_mutually_exclusive_group()
group.add_argument('--targets', action='store',
help='Comma separated list of VMs to target')
group.add_argument('--all', action='store_true',
help='Target all non-disposable VMs (TemplateVMs and '
'AppVMs)')
parser.add_argument('--templates', action='store_true',
help='Target all TemplatesVMs')
parser.add_argument('--standalones', action='store_true',
help='Target all StandaloneVMs')
parser.add_argument('--app', action='store_true',
help='Target all AppVMs')
parser.add_argument('command',
help='Salt command to execute (for example: '
'state.highstate)',
nargs=argparse.REMAINDER)
args = parser.parse_args(args)
if args.sync_extmods:
opts = qubessalt.load_opts()
# Doing it this way because the RunnerClient requires actual
# master opts, which we could load, but we want this to end
# up in the minion extension_modules dir. Don't assume defaults,
# don't load twice.
with ctx.func_globals_inject(saltutil.sync_all, __opts__=opts):
saltutil.sync_all()
if not args.skip_dom0:
try:
# TODO handle args.show_output - if false, log to some file
subprocess.check_call(['qubesctl', '--dom0-only'] + args.command)
except subprocess.CalledProcessError:
print("DOM0 configuration failed, not continuing", file=sys.stderr)
return 1
app = qubesadmin.Qubes()
# Load VM list only after dom0 salt call - some new VMs might be created
targets = []
if args.templates:
targets += [vm for vm in app.domains.values()
if vm.klass == 'TemplateVM']
if args.standalones:
targets += [vm for vm in app.domains.values()
if vm.klass == 'StandaloneVM']
if args.app:
targets += [vm for vm in app.domains.values()
if vm.klass == 'AppVM']
if args.all:
# all but DispVMs
targets = [vm for vm in app.domains.values()
if not vm.klass == 'DispVM']
elif args.targets:
names = args.targets.split(',')
targets = [vm for vm in app.domains.values() if vm.name in names]
# remove dom0 - already handled
targets = [vm for vm in targets if vm.name != 'dom0']
if args.show_output and args.force_color:
args.command.insert(0, '--force-color')
# templates first
vms_to_go = [vm for vm in targets
if vm.klass == 'TemplateVM']
runner = qubessalt.ManageVMRunner(app, vms_to_go, args.command,
show_output=args.show_output,
force_color=args.force_color,
max_concurrency=args.max_concurrency,
skip_top_check=args.skip_top_check)
exit_code = runner.run()
# then non-templates (AppVMs)
vms_to_go = [vm for vm in targets
if not vm.klass == 'TemplateVM']
runner = qubessalt.ManageVMRunner(app, vms_to_go, args.command,
show_output=args.show_output,
force_color=args.force_color,
max_concurrency=args.max_concurrency,
skip_top_check=args.skip_top_check)
return max(exit_code, runner.run())
if __name__ == '__main__':
# --dom0-only is a passthrough to salt-call
if len(sys.argv) > 1 and sys.argv[1] == '--dom0-only':
try:
import qubes.mgmt.patches
except ImportError:
pass
from salt.scripts import salt_call
sys.argv[1] = '--local'
salt_call()
else:
sys.exit(main())