diff --git a/.gitignore b/.gitignore index 1f6954d..9f16d51 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,53 @@ -SOURCES/initscripts-10.00.18.tar.gz +/initscripts-9.43.tar.bz2 +/initscripts-9.44.tar.bz2 +/initscripts-9.45.tar.bz2 +/initscripts-9.46.tar.bz2 +/initscripts-9.47.tar.bz2 +/initscripts-9.48.tar.bz2 +/initscripts-9.50.tar.bz2 +/initscripts-9.51.tar.bz2 +/initscripts-9.52.tar.bz2 +/initscripts-9.53.tar.bz2 +/initscripts-9.54.tar.bz2 +/initscripts-9.55.tar.bz2 +/initscripts-9.56.1.tar.bz2 +/initscripts-9.58.tar.bz2 +/initscripts-9.59.tar.bz2 +/initscripts-9.60.tar.bz2 +/initscripts-9.61.tar.bz2 +/initscripts-9.62.tar.bz2 +/initscripts-9.63.tar.bz2 +/initscripts-9.64.tar.bz2 +/initscripts-9.65.tar.bz2 +/initscripts-9.66.tar.bz2 +/initscripts-9.67.tar.bz2 +/initscripts-9.68.tar.bz2 +/initscripts-9.69.tar.bz2 +/initscripts-9.70.tar.gz +/initscripts-9.71.tar.gz +/initscripts-9.72.tar.gz +/initscripts-9.74.tar.gz +/initscripts-9.75.tar.gz +/initscripts-9.76.tar.gz +/initscripts-9.77.tar.gz +/initscripts-9.78.tar.gz +/initscripts-9.79.tar.gz +/initscripts-10.00.0.tar.gz +/initscripts-10.00.1.tar.gz +/initscripts-10.00.2.tar.gz +/initscripts-10.00.3.tar.gz +/initscripts-10.00.4.tar.gz +/initscripts-10.00.5.tar.gz +/initscripts-10.00.6.tar.gz +/initscripts-10.00.7.tar.gz +/initscripts-10.00.8.tar.gz +/initscripts-10.00.9.tar.gz +/initscripts-10.00.10.tar.gz +/initscripts-10.00.11.tar.gz +/initscripts-10.00.12.tar.gz +/initscripts-10.00.13.tar.gz +/initscripts-10.00.14.tar.gz +/initscripts-10.00.15.tar.gz +/initscripts-10.00.16.tar.gz +/initscripts-10.00.17.tar.gz /initscripts-10.00.18.tar.gz diff --git a/rebase.sh b/rebase.sh new file mode 100644 index 0000000..dc8412b --- /dev/null +++ b/rebase.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# We always do a rebase to new upstream's tarball for RHEL +# +# For non-currnet RHEL releases, we can sometimes backport specific patches, +# if the rebase is not possible, for example because of Z-Stream. +# +# This scripts automates this process. + +# Since we are operating in a dist-git repository where we can't fix things with +# --force-push if something goes wrong, we need to be extra careful and exit +# immediately if something fails. +set -e + +curl https://raw.githubusercontent.com/fedora-sysv/initscripts/rhel8-branch/initscripts.spec -o initscripts.spec || exit 1 +spectool -g initscripts.spec + +# FIXME: Temporarily disabled until we have reliable rhel-8 mock profile: +# +# Make a local scratch build in mock first. If it fails, do not upload new tarball! +#srpm_file="$(basename $(rhpkg-sha512 srpm | grep -i "wrote" | cut -d ':' -f 2))" +#arch="$(uname -p)" + +#mock -r "fedora-rawhide-${arch}" "${srpm_file}" || exit 2 + +# Scratch build passed, the build should pass in Koji as well. Let's proceed: +rhpkg-sha512 new-sources "$(basename $(spectool -S -l initscripts.spec | gawk '{print $2;}'))" || exit 3 +git add initscripts.spec +git commit -m "$(grep Version initscripts.spec | gawk '{print $2;}')" + +git show diff --git a/tests/Sanity-init-scripts-LSB/Makefile b/tests/Sanity-init-scripts-LSB/Makefile new file mode 100644 index 0000000..460c83f --- /dev/null +++ b/tests/Sanity-init-scripts-LSB/Makefile @@ -0,0 +1,64 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /CoreOS/initscripts/Sanity/init-scripts-LSB +# Description: Init scripts should meet LSB specifications +# Author: Yulia Kopkova +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2009 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# 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. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/CoreOS/initscripts/Sanity/init-scripts-LSB +export TESTVERSION=1.4 + +BUILT_FILES= + +FILES=$(METADATA) runtest.sh Makefile PURPOSE + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Jan Scotka " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Init scripts should meet LSB specifications" >> $(METADATA) + @echo "Type: Sanity" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RunFor: initscripts" >> $(METADATA) + @echo "Requires: initscripts" >> $(METADATA) + @echo "Priority: Normal" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + @echo "Confidential: no" >> $(METADATA) + @echo "Destructive: no" >> $(METADATA) + @echo "Releases: RedHatEnterpriseLinux6" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/Sanity-init-scripts-LSB/PURPOSE b/tests/Sanity-init-scripts-LSB/PURPOSE new file mode 100644 index 0000000..7246d5e --- /dev/null +++ b/tests/Sanity-init-scripts-LSB/PURPOSE @@ -0,0 +1,3 @@ +PURPOSE of /CoreOS/initscripts/Sanity/init-scripts-LSB +Description: Init scripts should meet LSB specifications +Author: Yulia Kopkova diff --git a/tests/Sanity-init-scripts-LSB/runtest.sh b/tests/Sanity-init-scripts-LSB/runtest.sh new file mode 100755 index 0000000..a2274d0 --- /dev/null +++ b/tests/Sanity-init-scripts-LSB/runtest.sh @@ -0,0 +1,228 @@ +#!/bin/bash +# vim: dict=/usr/share/rhts-library/dictionary.vim cpt=.,w,b,u,t,i,k +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# runtest.sh of /CoreOS/initscripts/Sanity/init-scripts-LSB +# Description: Init scripts should meet LSB specifications +# Author: Jan Scotka , Yulia Kopkova +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2009 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# 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. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include rhts environment +. /usr/bin/rhts-environment.sh +. /usr/share/rhts-library/rhtslib.sh + +PACKAGE="initscripts" + + +SRV_NETCONSOLE=netconsole +SRV_NETFS=netfs +TRG_REMOTEFS=remote-fs.target +SRV_NETWORK=network + +rlJournalStart + + rlPhaseStartSetup + rlAssertRpm $PACKAGE + rlRun "useradd testuserqa" 0 "Add test user" + rlFileBackup /etc/sysconfig/netconsole + if rlIsRHEL '<7'; then #there is no syslog in rhel7 and highier + rlRun "sed -i -e 's,^# SYSLOGADDR=,SYSLOGADDR=redhat.com,' /etc/sysconfig/netconsole" 0 "Set remote syslog server address /etc/sysconfig/netconsole" + fi + rlPhaseEnd + + + rlPhaseStartTest "netconsole service LSB compliance test" +if ls /lib*/modules/*/kernel/drivers/net/netconsole.ko*; then + rlRun "ls /lib*/modules/*/kernel/drivers/net/netconsole.ko*" 0 + if rlIsRHEL '<7'; then + + SERVICE=$SRV_NETCONSOLE + rlServiceStop $SERVICE + rlLog ">>>>>>>>> service start" + rlRun "service $SERVICE start" 0 " Service must start without problem " + rlRun "service $SERVICE status" 0 " Then Status command " + rlRun "service $SERVICE start" 0 " Already started service " + rlRun "service $SERVICE status" 0 " Again status command " + + rlLog ">>>>>>>>> service restart" + rlRun "service $SERVICE restart" 0 " Restarting of service " + rlRun "service $SERVICE status" 0 " Status command " + + rlLog ">>>>>>>>> service stop" + rlRun "service $SERVICE stop" 0 " Stopping service " + rlRun "service $SERVICE status" 3 " Status of stopped service " + rlRun "service $SERVICE stop" 0 " Stopping service again " + rlRun "service $SERVICE status" 3 " Status of stopped service " + + rlLog ">>>>>>>>> insufficient rights" + rlRun "service $SERVICE start " 0 " Starting service for restarting under nonpriv user " + rlRun "su testuserqa -c 'service $SERVICE restart'" 1 "Insufficient rights, restarting resrvice under nonprivileged user must fail " + + rlLog ">>>>>>>>> operations" + rlServiceStop $SERVICE + rlRun "service $SERVICE start" 0 " Service have to implement start function " + rlRun "service $SERVICE restart" 0 " Service have to implement restart function " + rlRun "service $SERVICE status" 0 " Service have to implement status function " + rlRun "service $SERVICE condrestart" 0 " Service have to implement condrestart function " + rlRun "service $SERVICE reload" 0 " Service have to implement reload function " + rlRun "service $SERVICE force-reload" 0 " Service have to implement force-reload function " + + rlLog ">>>>>>>>> nonexist operations" + rlRun "service $SERVICE noexistop" 2 " Testing proper return code when nonexisting function " + + rlServiceRestore $SERVICE + fi # rhel 6 or less +else + rlLog ">>>> no netconsole kernel module appear here" + rlRun "ls /lib*/modules/*/kernel/drivers/net/netconsole.ko*" 1,2 +fi + rlLog "NIC should support polling, NETPOLL should be compliled in kernel and netconsole module should be loaded" + rlLog "`cat /usr/src/kernels/$(uname -r)/.config | grep -i poll`" + rlLog "netconsole module: `lsmod | grep -i netconsole && echo true || echo false`" + rlLog "`cat /var/log/messages | grep -i netconsole | tail -n 10`" + rlPhaseEnd + + # for RHEL6 and lower + if rlIsRHEL '<7'; then + rlPhaseStartTest "netfs service LSB compliance test" + + SERVICE=$SRV_NETFS + rlServiceStop $SERVICE + rlLog ">>>>>>>>> service start" + rlRun "service $SERVICE start" 0 " Service must start without problem " + rlRun "service $SERVICE status" 0 " Then Status command " + rlRun "service $SERVICE start" 0 " Already started service " + rlRun "service $SERVICE status" 0 " Again status command " + + rlLog ">>>>>>>>> service restart" + rlRun "service $SERVICE restart" 0 " Restarting of service " + rlRun "service $SERVICE status" 0 " Status command " + + rlLog ">>>>>>>>> service stop" + rlRun "service $SERVICE stop" 0 " Stopping service " + rlRun "service $SERVICE status" 3 " Status of stopped service " + rlRun "service $SERVICE stop" 0 " Stopping service again " + rlRun "service $SERVICE status" 3 " Status of stopped service " + + rlLog ">>>>>>>>> insufficient rights" + rlRun "service $SERVICE start " 0 " Starting service for restarting under nonpriv user " + rlRun "su testuserqa -c 'service $SERVICE restart'" 4 "Insufficient rights, restarting resrvice under nonprivileged user must fail " + + rlLog ">>>>>>>>> operations" + rlServiceStop $SERVICE + rlRun "service $SERVICE start" 0 " Service have to implement start function " + rlRun "service $SERVICE restart" 0 " Service have to implement restart function " + rlRun "service $SERVICE status" 0 " Service have to implement status function " + + rlLog ">>>>>>>>> nonexist operations" + rlRun "service $SERVICE noexistop" 2 " Testing proper return code when nonexisting function " + + rlServiceRestore $SERVICE + + rlPhaseEnd + else + rlPhaseStartTest "remote-fs target LSB compliance test" + + TARGET=$TRG_REMOTEFS + rlServiceStop $TARGET + rlLog ">>>>>>>>> target start" + rlRun "service $TARGET start" 0 " Target must start without problem " + rlRun "service $TARGET status" 0 " Then Status command " + rlRun "service $TARGET start" 0 " Already started target " + rlRun "service $TARGET status" 0 " Again status command " + + rlLog ">>>>>>>>> target restart" + rlRun "service $TARGET restart" 0 " Restarting target " + rlRun "service $TARGET status" 0 " Status command " + + rlLog ">>>>>>>>> target stop" + rlRun "service $TARGET stop" 0 " Stopping target " + rlRun "service $TARGET status" 3 " Status of stopped target " + rlRun "service $TARGET stop" 0 " Stopping target again " + rlRun "service $TARGET status" 3 " Status of stopped target " + + rlLog ">>>>>>>>> insufficient rights" + rlRun "service $TARGET start " 0 " Starting target for restarting under nonpriv user " + rlRun "su testuserqa -c 'service $TARGET restart'" 1 " Insufficient rights, restarting target under nonprivileged user must fail " # returns 1 instead of 4 because of polkit + + rlLog ">>>>>>>>> operations" + rlServiceStop $TARGET + rlRun "service $TARGET start" 0 " Target have to implement start function " + rlRun "service $TARGET restart" 0 " Target have to implement restart function " + rlRun "service $TARGET status" 0 " Target have to implement status function " + + rlLog ">>>>>>>>> nonexist operations" + rlRun "service $TARGET noexistop" 2 " Testing proper return code when nonexisting function " + + rlServiceRestore $TARGET + + rlPhaseEnd + fi + + +# rlPhaseStartTest "$SRV_NETWORK service LSB compliance test" +# +# SERVICE=$SRV_NETWORK +# rlServiceStop $SERVICE +# rlLog ">>>>>>>>> service start" +# rlRun "service $SERVICE start" 0 " Service must start without problem " +# rlRun "service $SERVICE status" 0 " Then Status command " +# rlRun "service $SERVICE start" 1,0 " Already started service " +# rlRun "service $SERVICE status" 0 " Again status command " + +# rlLog ">>>>>>>>> service restart" +# rlRun "service $SERVICE restart" 0 " Restarting of service " +# rlRun "service $SERVICE status" 0 " Status command " + +# rlLog ">>>>>>>>> service stop" +# rlRun "service $SERVICE stop" 0 " Stopping service " +# rlRun "service $SERVICE status" 0 " Status of stopped service " +# rlRun "service $SERVICE stop" 0 " Stopping service again " +# rlRun "service $SERVICE status" 0 " Status of stopped service " + +# rlLog ">>>>>>>>> insufficient rights" +# rlRun "service $SERVICE start " 0 " Starting service for restarting under nonpriv user " +# rlRun "su testuserqa -c 'service $SERVICE restart'" 4 "Insufficient rights, restarting resrvice under nonprivileged user must fail " + +# rlLog ">>>>>>>>> operations" +# rlServiceStop $SERVICE +# rlRun "service $SERVICE start" 0 " Service have to implement start function " +# rlRun "service $SERVICE restart" 0 " Service have to implement restart function " +# rlRun "service $SERVICE status" 0 " Service have to implement status function " +# rlRun "service $SERVICE reload" 0 " Service have to implement reload function " +# rlRun "service $SERVICE force-reload" 0 " Service have to implement force-reload function " + +# rlLog ">>>>>>>>> nonexist operations" +# rlRun "service $SERVICE noexistop" 2 " Testing proper return code when nonexisting function " + +# rlServiceRestore $SERVICE +# service $SERVICE start + rlPhaseEnd + + + rlPhaseStartCleanup + rlRun "userdel -fr testuserqa" 0 "Remove test user" + rlFileRestore + rlPhaseEnd + +rlJournalPrintText +rlJournalEnd diff --git a/tests/standard-inventory-qcow2 b/tests/standard-inventory-qcow2 new file mode 100755 index 0000000..a9e2c64 --- /dev/null +++ b/tests/standard-inventory-qcow2 @@ -0,0 +1,291 @@ +#!/usr/bin/env python + +import argparse +import errno +import json +import os +import shutil +import shlex +import signal +import socket +import subprocess +import sys +import tempfile +import time +import distutils.util + +IDENTITY = """ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA1DrTSXQRF8isQQfPfK3U+eFC4zBrjur+Iy15kbHUYUeSHf5S +jXPYbHYqD1lHj4GJajC9okle9rykKFYZMmJKXLI6987wZ8vfucXo9/kwS6BDAJto +ZpZSj5sWCQ1PI0Ce8CbkazlTp5NIkjRfhXGP8mkNKMEhdNjaYceO49ilnNCIxhpb +eH5dH5hybmQQNmnzf+CGCCLBFmc4g3sFbWhI1ldyJzES5ZX3ahjJZYRUfnndoUM/ +TzdkHGqZhL1EeFAsv5iV65HuYbchch4vBAn8jDMmHh8G1ixUCL3uAlosfarZLLyo +3HrZ8U/llq7rXa93PXHyI/3NL/2YP3OMxE8baQIDAQABAoIBAQCxuOUwkKqzsQ9W +kdTWArfj3RhnKigYEX9qM+2m7TT9lbKtvUiiPc2R3k4QdmIvsXlCXLigyzJkCsqp +IJiPEbJV98bbuAan1Rlv92TFK36fBgC15G5D4kQXD/ce828/BSFT2C3WALamEPdn +v8Xx+Ixjokcrxrdeoy4VTcjB0q21J4C2wKP1wEPeMJnuTcySiWQBdAECCbeZ4Vsj +cmRdcvL6z8fedRPtDW7oec+IPkYoyXPktVt8WsQPYkwEVN4hZVBneJPCcuhikYkp +T3WGmPV0MxhUvCZ6hSG8D2mscZXRq3itXVlKJsUWfIHaAIgGomWrPuqC23rOYCdT +5oSZmTvFAoGBAPs1FbbxDDd1fx1hisfXHFasV/sycT6ggP/eUXpBYCqVdxPQvqcA +ktplm5j04dnaQJdHZ8TPlwtL+xlWhmhFhlCFPtVpU1HzIBkp6DkSmmu0gvA/i07Z +pzo5Z+HRZFzruTQx6NjDtvWwiXVLwmZn2oiLeM9xSqPu55OpITifEWNjAoGBANhH +XwV6IvnbUWojs7uiSGsXuJOdB1YCJ+UF6xu8CqdbimaVakemVO02+cgbE6jzpUpo +krbDKOle4fIbUYHPeyB0NMidpDxTAPCGmiJz7BCS1fCxkzRgC+TICjmk5zpaD2md +HCrtzIeHNVpTE26BAjOIbo4QqOHBXk/WPen1iC3DAoGBALsD3DSj46puCMJA2ebI +2EoWaDGUbgZny2GxiwrvHL7XIx1XbHg7zxhUSLBorrNW7nsxJ6m3ugUo/bjxV4LN +L59Gc27ByMvbqmvRbRcAKIJCkrB1Pirnkr2f+xx8nLEotGqNNYIawlzKnqr6SbGf +Y2wAGWKmPyEoPLMLWLYkhfdtAoGANsFa/Tf+wuMTqZuAVXCwhOxsfnKy+MNy9jiZ +XVwuFlDGqVIKpjkmJyhT9KVmRM/qePwgqMSgBvVOnszrxcGRmpXRBzlh6yPYiQyK +2U4f5dJG97j9W7U1TaaXcCCfqdZDMKnmB7hMn8NLbqK5uLBQrltMIgt1tjIOfofv +BNx0raECgYEApAvjwDJ75otKz/mvL3rUf/SNpieODBOLHFQqJmF+4hrSOniHC5jf +f5GS5IuYtBQ1gudBYlSs9fX6T39d2avPsZjfvvSbULXi3OlzWD8sbTtvQPuCaZGI +Df9PUWMYZ3HRwwdsYovSOkT53fG6guy+vElUEDkrpZYczROZ6GUcx70= +-----END RSA PRIVATE KEY----- +""" + +USER_DATA = """#cloud-config +users: + - default + - name: root + groups: sudo + shell: /bin/bash + ssh_authorized_keys: + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUOtNJdBEXyKxBB898rdT54ULjMGuO6v4jLXmRsdRhR5Id/lKNc9hsdioPWUePgYlqML2iSV72vKQoVhkyYkpcsjr3zvBny9+5xej3+TBLoEMAm2hmllKPmxYJDU8jQJ7wJuRrOVOnk0iSNF+FcY/yaQ0owSF02Nphx47j2KWc0IjGGlt4fl0fmHJuZBA2afN/4IYIIsEWZziDewVtaEjWV3InMRLllfdqGMllhFR+ed2hQz9PN2QcapmEvUR4UCy/mJXrke5htyFyHi8ECfyMMyYeHwbWLFQIve4CWix9qtksvKjcetnxT+WWrutdr3c9cfIj/c0v/Zg/c4zETxtp standard-test-qcow2 +ssh_pwauth: True +chpasswd: + list: | + root:foobar + expire: False +runcmd: + - mkfs.ext4 /dev/sdb + - mount /dev/sdb /usr/local + - sudo mount -o remount,rw /usr + - mkdir /expected /output +""" + +def main(argv): + parser = argparse.ArgumentParser(description="Inventory for a QCow2 test image") + parser.add_argument("--list", action="store_true", help="Verbose output") + parser.add_argument('--host', help="Get host variables") + parser.add_argument("subjects", nargs="*", default=shlex.split(os.environ.get("TEST_SUBJECTS", ""))) + opts = parser.parse_args() + + try: + if opts.host: + data = host(opts.host) + else: + data = list(opts.subjects) + sys.stdout.write(json.dumps(data, indent=4, separators=(',', ': '))) + except RuntimeError as ex: + sys.stderr.write("{0}: {1}\n".format(os.path.basename(sys.argv[0]), str(ex))) + return 1 + + return 0 + + +def list(subjects): + hosts = [] + variables = {} + for subject in subjects: + if subject.endswith((".qcow2", ".qcow2c")): + vars = host(subject) + if vars: + hosts.append(subject) + variables[subject] = vars + return {"localhost": {"hosts": hosts, "vars": {}}, "subjects": {"hosts": hosts, "vars": {}}, + "_meta": {"hostvars": variables}} + + +def start_qemu(image, cloudinit, log, disk_directory=None, disk_size=None, portrange=(2222, 5555)): + for port in xrange(*portrange): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + try: + sock.bind(("127.0.0.3", port)) + + if disk_size: + return subprocess.Popen(["/usr/bin/qemu-system-x86_64", "-m", "1024", image, + "-enable-kvm", "-snapshot", "-cdrom", cloudinit, + "-hdb", disk_directory, + "-net", "nic,model=virtio", "-net", + "user,hostfwd=tcp:127.0.0.3:{0}-:22".format(port), + "-device", "isa-serial,chardev=pts2", "-chardev", "file,id=pts2,path=" + log, + "-display", "none"], stdout=open(os.devnull, 'w')), port + else: + return subprocess.Popen(["/usr/bin/qemu-system-x86_64", "-m", "1024", image, + "-enable-kvm", "-snapshot", "-cdrom", cloudinit, + "-net", "nic,model=virtio", "-net", + "user,hostfwd=tcp:127.0.0.3:{0}-:22".format(port), + "-device", "isa-serial,chardev=pts2", "-chardev", "file,id=pts2,path=" + log, + "-display", "none"], stdout=open(os.devnull, 'w')), port + except IOError: + pass + finally: + sock.close() + else: + raise RuntimeError("unable to find free local port to map SSH to") + + +def host(image): + null = open(os.devnull, 'w') + + try: + tty = os.open("/dev/tty", os.O_WRONLY) + os.dup2(tty, 2) + except OSError: + tty = None + pass + + # A directory for temporary stuff + directory = tempfile.mkdtemp(prefix="inventory-cloud") + identity = os.path.join(directory, "identity") + with open(identity, 'w') as f: + f.write(IDENTITY) + os.chmod(identity, 0o600) + metadata = os.path.join(directory, "meta-data") + with open(metadata, 'w') as f: + f.write("") + userdata = os.path.join(directory, "user-data") + with open(userdata, 'w') as f: + f.write(USER_DATA) + + # Create additional disk + disk_size = None + disk_directory = None + try: + disk_size = os.environ.get("EXTEND_DISK_SIZE") + if disk_size: + sys.stderr.write("\nCreate additional cloud init disk DISK SIZE {}\n".format(disk_size)) + + disk_directory = "{}/atomic-host-disk2-{}".format(directory, disk_size) + subprocess.check_call(["qemu-img", "create", "-f", "qcow2", disk_directory, disk_size], stdout=null) + + except KeyError: + sys.stderr.write("\nCouldn't create additional cloud init disk DISK SIZE\n") + pass + + # Create our cloud init so we can log in + cloudinit = os.path.join(directory, "cloud-init.iso") + subprocess.check_call(["/usr/bin/genisoimage", "-input-charset", "utf-8", + "-volid", "cidata", "-joliet", "-rock", "-quiet", + "-output", cloudinit, userdata, metadata], stdout=null) + + # Determine if virtual machine should be kept available for diagnosis after completion + try: + diagnose = distutils.util.strtobool(os.getenv("TEST_DEBUG", "0")) + except ValueError: + diagnose = 0 + + sys.stderr.write("Launching virtual machine for {0}\n".format(image)) + + # And launch the actual VM + artifacts = os.environ.get("TEST_ARTIFACTS", os.path.join(os.getcwd(), "artifacts")) + try: + os.makedirs(artifacts) + except OSError as exc: + if exc.errno != errno.EEXIST or not os.path.isdir(artifacts): + raise + log = os.path.join(artifacts, "{0}.log".format(os.path.basename(image))) + + proc = None # for failure detection + cpe = None # for exception scoping + for tries in xrange(0, 5): + try: + proc, port = start_qemu(image, cloudinit, log, disk_directory=disk_directory, disk_size=disk_size) + break + except subprocess.CalledProcessError as cpe: + time.sleep(1) + continue + if proc is None: + raise RuntimeError("Could not launch VM for qcow2 image" + " '{0}':{1}".format(image, cpe.output)) + + # The variables + variables = {"ansible_ssh_port": "{0}".format(port), + "ansible_ssh_host": "127.0.0.3", + "ansible_ssh_user": "root", + "ansible_ssh_pass": "foobar", + "ansible_ssh_private_key_file": identity, + "ansible_ssh_common_args": "-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"} + + # Write out a handy inventory file, for our use and for debugging + args = " ".join(["{0}='{1}'".format(*item) for item in variables.items()]) + inventory = os.path.join(directory, "inventory") + with open(inventory, "w") as f: + f.write("[subjects]\nlocalhost {1}\n".format(image, args)) + + # Wait for ssh to come up + ping = ["/usr/bin/ansible", "--inventory", inventory, "localhost", "--module-name", "raw", "--args", "/bin/true"] + + for tries in xrange(0, 30): + try: + (pid, ret) = os.waitpid(proc.pid, os.WNOHANG) + if pid != 0: + raise RuntimeError("qemu failed to launch qcow2 image: {0}".format(image)) + subprocess.check_call(ping, stdout=null, stderr=null) + break + except subprocess.CalledProcessError: + time.sleep(3) + else: + # Kill the qemu process + try: + os.kill(proc.pid, signal.SIGTERM) + except OSError: + pass + raise RuntimeError("could not access launched qcow2 image: {0}".format(image)) + + # Process of our parent + ppid = os.getppid() + + child = os.fork() + if child: + return variables + + # Daemonize and watch the processes + os.chdir("/") + os.setsid() + os.umask(0) + + if tty is None: + tty = null.fileno() + + # Duplicate standard input to standard output and standard error. + os.dup2(null.fileno(), 0) + os.dup2(tty, 1) + os.dup2(tty, 2) + + # Now wait for the parent process to go away, then kill the VM + while True: + time.sleep(3) + try: + os.kill(ppid, 0) + os.kill(proc.pid, 0) + except OSError: + break # Either of the processes no longer exist + + if diagnose: + sys.stderr.write("\n") + sys.stderr.write("DIAGNOSE: ssh -p {0} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null " + "root@{1} # password: {2}\n".format(port, "127.0.0.3", "foobar")) + sys.stderr.write("DIAGNOSE: export ANSIBLE_INVENTORY={0}\n".format(inventory)) + sys.stderr.write("DIAGNOSE: kill {0} # when finished\n".format(os.getpid())) + + def _signal_handler(*args): + sys.stderr.write("\nDIAGNOSE ending...\n") + + signal.signal(signal.SIGTERM, _signal_handler) + signal.pause() + + # Kill the qemu process + try: + os.kill(proc.pid, signal.SIGTERM) + except OSError: + pass + + shutil.rmtree(directory) + sys.exit(0) + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100644 index 0000000..2e7b831 --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,12 @@ +--- +- hosts: localhost + roles: + - role: standard-test-beakerlib + tags: + - classic + - container + - atomic + tests: + - Sanity-init-scripts-LSB + required_packages: + - initscripts