Skip to content

Commit

Permalink
Extend qubesctl to configure also VMs
Browse files Browse the repository at this point in the history
This commit uses salt-ssh (running over qrexec) called from "DispVM" to
configure VMs. For that to work, DispVM gets copy of Salt configuration
(mostly full configuration - the only exception is pillars, filtered at
 dom0 side).

Fixes QubesOS/qubes-issues#1541
  • Loading branch information
marmarek committed May 1, 2016
1 parent b981fa0 commit 0e35693
Show file tree
Hide file tree
Showing 9 changed files with 505 additions and 8 deletions.
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ install-custom::
cp -Tr etc $(DESTDIR)/etc
cp -Tr srv $(DESTDIR)/srv

.PHONY: install-vm
install-vm:
install -d $(DESTDIR)/usr/lib/qubes-vm-connector/ssh-wrapper
install ssh-wrapper $(DESTDIR)/usr/lib/qubes-vm-connector/ssh-wrapper/ssh
ln -s ssh $(DESTDIR)/usr/lib/qubes-vm-connector/ssh-wrapper/scp
ln -s /bin/true $(DESTDIR)/usr/lib/qubes-vm-connector/ssh-wrapper/ssh-keygen
install -d $(DESTDIR)/etc/qubes-rpc
install qubes.SaltLinuxVM $(DESTDIR)/etc/qubes-rpc

.PHONY: install-dom0
install-dom0:
python setup.py install -O1 --root $(DESTDIR)

.PHONY: get-sources
get-sources: GIT_REPOS := $(addprefix $(SRC_DIR)/,$(MGMT_SALT_COMPONENTS) mgmt-salt-app-saltstack)
get-sources:
Expand Down
42 changes: 42 additions & 0 deletions qubes.SaltLinuxVM
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env bash
#
# The Qubes OS Project, https://www.qubes-os.org/
#
# Copyright (C) 2016 Marek Marczykowski-Górecki
# <[email protected]>
#
# q program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

set -e

if [ "`id -u`" -ne 0 ]; then
exec sudo "$0" "$@"
fi

read target_vm
read salt_command

rm -rf /srv
mv /home/user/QubesIncoming/dom0/srv /srv
if [ -f /srv/master ]; then
mv /srv/master /etc/salt/
fi
(cd /srv/salt; find _tops -type f -o -type l| sed -e 's/^/- /' > tops.yaml)
cat > /etc/salt/roster <<EOF
$target_vm:
host: $target_vm
EOF
export PATH="/usr/lib/qubes-vm-connector/ssh-wrapper:$PATH"
salt-ssh "$target_vm" $salt_command
90 changes: 82 additions & 8 deletions qubesctl
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,91 @@
Directly call a salt command in the modules, does not require a running salt
minion to run.
'''

try:
import qubes.mgmt.patches
except ImportError:
pass
import argparse

import sys
sys.argv.insert(1, '--local')
import subprocess
import qubessalt
import qubes.qubes


def main(args=None):
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 condifuration (VM creation etc)')
group = parser.add_mutually_exclusive_group()
group.add_argument('--targets', action='store',
help='Coma separated list of VMs to target')
group.add_argument('--templates', action='store_true',
help='Target all templates')
group.add_argument('--app', action='store_true',
help='Target all AppVMs')
group.add_argument('--all', action='store_true',
help='Target all non-disposable VMs (TemplateVMs and AppVMs)')
parser.add_argument('command',
help='Salt command to execute (for example: state.highstate)',
nargs=argparse.REMAINDER)
args = parser.parse_args(args)

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 >>sys.stderr, "DOM0 configuration failed, not continuing"
return 1

# Load VM list only after dom0 salt call - some new VMs might be created
qc = qubes.qubes.QubesVmCollection()
qc.lock_db_for_reading()
qc.load()
qc.unlock_db()

targets = []
if args.templates:
targets = [vm for vm in qc.values() if vm.is_template()]
elif args.app:
targets = [vm for vm in qc.values() if vm.is_appvm()]
elif args.targets:
names = args.targets.split(',')
targets = [vm for vm in qc.values() if vm.name in names]
elif args.all:
# all but DispVMs
targets = [vm for vm in qc.values() if not vm.is_disposablevm()]

# remove dom0 - already handled
if qc[0] in targets:
targets.remove(qc[0])

if args.show_output and args.force_color:
args.command.insert(0, '--force-color')

from salt.scripts import salt_call
# templates first
vms_to_go = [vm for vm in targets if vm.is_template()]
runner = qubessalt.ManageVMRunner(qc, vms_to_go, args.command,
show_output=args.show_output, force_color=args.force_color)
runner.run()
# then non-templates (AppVMs)
vms_to_go = [vm for vm in targets if not vm.is_template()]
runner = qubessalt.ManageVMRunner(qc, vms_to_go, args.command,
show_output=args.show_output, force_color=args.force_color)
runner.run()

# TODO: return meaningful exit code

if __name__ == '__main__':
salt_call()
# --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:
main()
Loading

0 comments on commit 0e35693

Please sign in to comment.