| |
@@ -12,7 +12,6 @@
|
| |
import sys
|
| |
import tempfile
|
| |
import time
|
| |
- import traceback
|
| |
import distutils.util
|
| |
|
| |
IDENTITY = """
|
| |
@@ -49,6 +48,8 @@
|
| |
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
|
| |
@@ -58,11 +59,14 @@
|
| |
expire: False
|
| |
"""
|
| |
|
| |
+
|
| |
def main(argv):
|
| |
- parser = argparse.ArgumentParser(description="Inventory for a QCow2 test image")
|
| |
+ 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", "")))
|
| |
+ parser.add_argument("subjects", nargs="*", default=shlex.split(
|
| |
+ os.environ.get("TEST_SUBJECTS", "")))
|
| |
opts = parser.parse_args()
|
| |
|
| |
try:
|
| |
@@ -72,44 +76,55 @@
|
| |
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)))
|
| |
+ sys.stderr.write("{0}: {1}\n".format(os.path.basename(sys.argv[0]),
|
| |
+ str(ex)))
|
| |
return 1
|
| |
|
| |
return 0
|
| |
|
| |
+
|
| |
def list(subjects):
|
| |
- hosts = [ ]
|
| |
- variables = { }
|
| |
+ 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 } }
|
| |
+ return {"localhost": {"hosts": hosts, "vars": {}},
|
| |
+ "subjects": {"hosts": hosts, "vars": {}},
|
| |
+ "_meta": {"hostvars": variables}}
|
| |
|
| |
|
| |
- def start_qemu(image, cloudinit, log, portrange=(2222, 5555)):
|
| |
+ def start_qemu(image, cloudinit, log, disk_directory="",
|
| |
+ 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)
|
| |
+
|
| |
+ # Shape cmd to start qemu
|
| |
+ disk_name = "" if disk_directory == "" else "-hdb"
|
| |
+
|
| |
+ cmd = ("/usr/bin/qemu-system-x86_64 -m 1024 {0} -enable-kvm "
|
| |
+ "-snapshot -cdrom {1} {2} {3} "
|
| |
+ "-net nic,model=virtio -net "
|
| |
+ "user,hostfwd=tcp:127.0.0.3:{4}-:22 -device "
|
| |
+ "isa-serial,chardev=pts2 -chardev "
|
| |
+ "file,id=pts2,path={5} -display none").format(
|
| |
+ image, cloudinit, disk_name, disk_directory, port, log).split()
|
| |
+
|
| |
try:
|
| |
sock.bind(("127.0.0.3", port))
|
| |
+ return subprocess.Popen(cmd, stdout=open(os.devnull, 'w')), port
|
| |
+
|
| |
except IOError:
|
| |
pass
|
| |
- else:
|
| |
- break
|
| |
finally:
|
| |
sock.close()
|
| |
else:
|
| |
raise RuntimeError("unable to find free local port to map SSH to")
|
| |
|
| |
- 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
|
| |
-
|
| |
|
| |
def host(image):
|
| |
null = open(os.devnull, 'w')
|
| |
@@ -134,13 +149,31 @@
|
| |
with open(userdata, 'w') as f:
|
| |
f.write(USER_DATA)
|
| |
|
| |
+ # Create additional disk if environment variable EXTEND_DISK_SIZE
|
| |
+ # was provided.
|
| |
+ # Optional suffixes "k" or "K" (kilobyte, 1024) "M" (megabyte, 1024k) and
|
| |
+ # "G" (gigabyte, 1024M) and T (terabyte, 1024G) are supported.
|
| |
+ disk_size = os.environ.get("EXTEND_DISK_SIZE")
|
| |
+ disk_directory = "{}/atomic-host-disk2-{}".format(directory, disk_size)
|
| |
+ try:
|
| |
+ subprocess.check_call([
|
| |
+ "qemu-img", "create", "-f", "qcow2", disk_directory, disk_size],
|
| |
+ stdout=null)
|
| |
+ sys.stderr.write(
|
| |
+ "\nCreate additional cloud init disk DISK SIZE {}\n".format(
|
| |
+ disk_size))
|
| |
+ except TypeError:
|
| |
+ disk_directory =""
|
| |
+
|
| |
# 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)
|
| |
+ "-output", cloudinit, userdata, metadata],
|
| |
+ stdout=null)
|
| |
|
| |
- # Determine if virtual machine should be kept available for diagnosis after completion
|
| |
+ # Determine if virtual machine should be kept available for diagnosis after
|
| |
+ # completion
|
| |
try:
|
| |
diagnose = distutils.util.strtobool(os.getenv("TEST_DEBUG", "0"))
|
| |
except ValueError:
|
| |
@@ -149,7 +182,8 @@
|
| |
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"))
|
| |
+ artifacts = os.environ.get("TEST_ARTIFACTS", os.path.join(os.getcwd(),
|
| |
+ "artifacts"))
|
| |
try:
|
| |
os.makedirs(artifacts)
|
| |
except OSError as exc:
|
| |
@@ -161,7 +195,8 @@
|
| |
cpe = None # for exception scoping
|
| |
for tries in xrange(0, 5):
|
| |
try:
|
| |
- proc, port = start_qemu(image, cloudinit, log)
|
| |
+ proc, port = start_qemu(image, cloudinit, log,
|
| |
+ disk_directory=disk_directory)
|
| |
break
|
| |
except subprocess.CalledProcessError as cpe:
|
| |
time.sleep(1)
|
| |
@@ -170,45 +205,38 @@
|
| |
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:
|
| |
- # 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"
|
| |
- ]
|
| |
-
|
| |
(pid, ret) = os.waitpid(proc.pid, os.WNOHANG)
|
| |
if pid != 0:
|
| |
- raise RuntimeError("qemu failed to launch qcow2 image: {0}".format(image))
|
| |
+ 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:
|
| |
- raise RuntimeError("could not access launched qcow2 image: {0}".format(image))
|
| |
+ raise RuntimeError(
|
| |
+ "could not access launched qcow2 image: {0}".format(image))
|
| |
|
| |
# Process of our parent
|
| |
ppid = os.getppid()
|
| |
@@ -233,18 +261,22 @@
|
| |
# 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
|
| |
+ 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()))
|
| |
+ 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")
|
| |
@@ -261,5 +293,6 @@
|
| |
shutil.rmtree(directory)
|
| |
sys.exit(0)
|
| |
|
| |
+
|
| |
if __name__ == '__main__':
|
| |
sys.exit(main(sys.argv))
|
| |
To test this feature the environment variable has to be exported:
export EXTEND_DISK_SIZE=8G
Any disk size can be set according to the
qemu-img
documentation.Additional space will be mounted to the /var/lib/docker