def force_rm(path): path = os.path.abspath(path) call_no_print(["sudo", "python", "-c", """ from __future__ import with_statement assert __name__ == "__main__" import sys import os import subprocess import time path, = sys.argv[1:] while True: commands = [] for proc in os.listdir("/proc"): if not proc.isdigit(): continue try: root = os.readlink(os.path.join("/proc", proc, "root")) except Exception, e: print ":::", e continue if root == path or root.startswith(path + "/"): commands.append(["kill", "-KILL", proc]) continue for fd in os.listdir(os.path.join("/proc", proc, "fd")): try: fdpath = os.readlink(os.path.join("/proc", proc, "fd", fd)) if not fdpath.startswith("/"): continue fdpath = os.path.join(root, fdpath[1:]) if path == fdpath or fdpath.startswith(path + "/"): commands.append(["kill", "-KILL", proc]) break except Exception, e: print ":::", e to_unmount = [] with open("/proc/mounts", "rb") as fh: for mount in fh: src, dst, rst = mount.split(" ", 2) if dst == path or dst.startswith(path + "/"): to_unmount.append(dst) to_unmount.sort(reverse=True) for mpath in to_unmount: commands.append(["umount", mpath]) if len(commands) == 0: break commands.append(["rm", "-rf", "--one-file-system", path]) all_good = True for command in commands: try: subprocess.check_call(command) except Exception, e: print ":::", e all_good = False if not all_good: time.sleep(0.1) """, path]) call(["sudo", "rm", "-rf", "--one-file-system", path])
def get_vm_state(vm_name, on_no_state=on_error_raise): assert " " not in vm_name, vm_name out = call_no_print(["virsh", "--connect", "lxc://", "list", "--all"]) out = out.split("\r\n") assert out[0].split() == ["Id", "Name", "State"], out assert out[1] == "-" * 52, out out = out[2:] for line in out: if line == "": continue parts = line.split() id, name, state = parts[0], parts[1], " ".join(parts[2:]) if name != vm_name: continue return state return on_no_state("No state found for vm: %s" % (vm_name,))
def prepare(config): def flush_cache(): if config["do_write_project_cache"]: call_no_print( ["mkdir", "-p", os.path.dirname(config["project_cache_path"])]) with open(config["project_cache_path"], "wb") as fh: fh.write(json.dumps(config["project_cache"])) flush_cache() root_path = os.path.join(config["project_dir"], "root") flush_cache() if not os.path.exists(root_path): force_rm(root_path) mnt_path = config["mnt_path"] force_rm(mnt_path) call(["mkdir", "-p", root_path]) call(["mkdir", "-p", mnt_path]) call(["sudo", "mount", "--bind", root_path, mnt_path]) call(["sudo", "debootstrap", config["ubuntu-codename"], mnt_path], stdout=None, stderr=None, stdin=None) for relpath in ["proc", "dev", "dev/pts", "sys"]: src = os.path.join("/", relpath) dst = os.path.join(mnt_path, relpath) call(["sudo", "mkdir", "-p", dst]) call(["sudo", "mount", "--bind", src, dst]) resolvconf = os.path.join(mnt_path, "run/resolvconf/resolv.conf") force_rm(resolvconf) call(["sudo", "cp", "/etc/resolv.conf", resolvconf]) call(["sudo", "bash", "-c", 'echo "$1" > "$2"', "-", aptconfig.BLANK_SOURCES, os.path.join(mnt_path, "etc/apt/sources.list")]) base_sources_config = copy.deepcopy(aptconfig.DEFAULT_CONFIG) base_sources_config["distribution"] = config["ubuntu-codename"] base_sources = aptconfig.render_to_sources_list(base_sources_config) call(["sudo", "bash", "-c", 'echo "$1" > "$2"', "-", base_sources, os.path.join(mnt_path, "etc/apt/sources.list.d/base.list")]) call(["sudo", "chroot", mnt_path, "apt-get", "update"], stdout=None) call(["sudo", "chroot", mnt_path, "apt-get", "remove", "--yes", "cloud-init"], stdout=None) call(["sudo", "chroot", mnt_path, "apt-get", "install", "--yes", "language-pack-en"], stdout=None) call(["sudo", "chroot", mnt_path, "apt-get", "install", "--yes", "openssh-server"], stdout=None) call(["sudo", "chroot", mnt_path, "adduser", "--gecos", "", "--disabled-password", "--uid", "1000", "sysadmin"], stdout=None) call(["sudo", "mv", os.path.join(mnt_path, "home", "sysadmin"), os.path.join(config["project_dir"], "home")]) call(["sudo", "chroot", mnt_path, "adduser", "sysadmin", "adm"], stdout=None) call(["sudo", "chroot", mnt_path, "adduser", "sysadmin", "sudo"], stdout=None) call(["sudo", "chroot", mnt_path, "bash", "-c", "rm -rf /etc/ssh/ssh_host_*"]) call(["sudo", "chroot", mnt_path, "dpkg-reconfigure", "openssh-server"], stdout=None) call(["cp", os.path.join(mnt_path, "etc", "ssh", "ssh_host_ecdsa_key.pub"), config["host_key_path"]]) call(["bash", "-c", 'echo basebox $(cat "$1") > "$2"', "-", config["host_key_path"], config["host_key_path"] + ".known"]) force_rm(config["ssh_key_path"]) call(["ssh-keygen", "-P", "", "-f", config["ssh_key_path"]]) for home_path in [os.path.join(mnt_path, "root"), os.path.join(config["project_dir"], "home")]: ak_path = os.path.join(home_path, ".ssh", "authorized_keys") call(["sudo", "mkdir", "-p", os.path.dirname(ak_path)]) force_rm(ak_path) call(["sudo", "cp", config["ssh_key_path"] + ".pub", ak_path]) if os.path.basename(home_path) != "root": call(["sudo", "chown", "-R", "1000:1000", os.path.dirname(ak_path)]) call(["sudo", "bash", "-c", 'echo "$1" > "$2"', "-", """\ auto lo iface lo inet loopback auto eth0 iface eth0 inet static address 192.168.122.200 netmask 255.255.255.0 network 192.168.122.0 gateway 192.168.122.1 dns-nameservers 192.168.122.1 """, os.path.join(mnt_path, "etc", "network", "interfaces")]) nopasswd_path = os.path.join( mnt_path, "etc", "sudoers.d", "sudo-nopasswd") call(["sudo", "bash", "-c", 'echo "$1" > "$2"', "-", """\ %sudo ALL=(ALL:ALL) NOPASSWD: ALL """, nopasswd_path]) call(["sudo", "chmod", "0440", nopasswd_path]) #### Run chef here? force_rm(mnt_path) if get_vm_state(config["vm_name"], on_no_state=lambda m: None) != "running": mnt_path = config["mnt_path"] force_rm(mnt_path) call(["mkdir", "-p", mnt_path]) call(["sudo", "mount", "--bind", root_path, mnt_path]) home_rw = os.path.join(config["project_dir"], "home") call(["mkdir", "-p", home_rw]) home_mnt = os.path.join(mnt_path, "home", "sysadmin") force_rm(home_mnt) call(["sudo", "mkdir", "-p", home_mnt]) call(["sudo", "mount", "--bind", home_rw, home_mnt]) call(["virsh", "--connect", "lxc://", "destroy", config["vm_name"]], do_check=False) while True: if get_vm_state(config["vm_name"], on_no_state=lambda m: "shut off") == "shut off": break time.sleep(0.1) call(["virsh", "--connect", "lxc://", "undefine", config["vm_name"]], do_check=False) definition = """\ <domain type="lxc"> <name>TEMPLATE: name</name> <memory>524288</memory> <os> <type arch="x86_64">exe</type> <init>/sbin/init</init> </os> <vcpu>2</vcpu> <clock offset="utc"/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>destroy</on_crash> <devices> <emulator>/usr/lib/libvirt/libvirt_lxc</emulator> <filesystem type="mount"> <source dir="TEMPLATE: root_dir"/> <target dir="/"/> </filesystem> <interface type="bridge"> <source bridge="virbr0"/> </interface> <console type="pty"> <target port="0"/> </console> </devices> </domain> """ xml = lxml.etree.fromstring(definition) for match in xml.xpath(".//name"): match.text = config["vm_name"] for match in xml.xpath(".//filesystem//source"): match.attrib["dir"] = mnt_path xml_path = os.path.join(config["project_dir"], "libvirt.xml") call(["bash", "-c", 'echo "$1" > "$2"', "-", lxml.etree.tostring(xml), xml_path]) call(["virsh", "--connect", "lxc://", "define", xml_path]) call(["virsh", "--connect", "lxc://", "start", config["vm_name"]]) print "~~~", " ".join(shell_escape(a) for a in get_ssh_argv(config)) while True: rc = [] call_no_print(get_ssh_argv(config, ["true"]), do_check=False, handle_rc=rc.append) rc = rc[0] if rc == 0: break time.sleep(0.1)
def flush_cache(): if config["do_write_project_cache"]: call_no_print( ["mkdir", "-p", os.path.dirname(config["project_cache_path"])]) with open(config["project_cache_path"], "wb") as fh: fh.write(json.dumps(config["project_cache"]))
from jwalutil import read_file from process import call as call_no_print from process import shell_escape import aptconfig import copy import hashlib import json import lxml.etree import optparse import os import shutil import sys import tempfile import time call = lambda *a, **kw: call_no_print( *a, **dict(kw.items() + [("do_print", True)])) def force_rm(path): path = os.path.abspath(path) call_no_print(["sudo", "python", "-c", """ from __future__ import with_statement assert __name__ == "__main__" import sys import os import subprocess import time path, = sys.argv[1:] while True: commands = [] for proc in os.listdir("/proc"): if not proc.isdigit():