def main(argv): parser = optparse.OptionParser(__doc__) parser.add_option("--tear-down", dest="tear_down_dir") parser.add_option("--show-config", dest="do_show_config", action="store_const", const=True, default=False) parser.add_option("--show-ssh-cmd", dest="do_show_ssh_cmd", action="store_const", const=True, default=False) parser.allow_interspersed_args = False options, args = parser.parse_args(argv) if len(args) == 0: args = ["bash"] if options.tear_down_dir is not None: force_rm(options.tear_down_dir) return config_path = find_config_path(on_not_found=parser.error) config = json.loads(read_file(config_path)) config.setdefault("project_path", os.path.dirname(config_path)) config.setdefault("cwd", os.path.abspath(".")) config.setdefault("home", os.path.abspath(os.path.expanduser("~"))) expand_config(config) if options.do_show_config: print json.dumps(config, indent=2, sort_keys=True) return if options.do_show_ssh_cmd: ssh_argv = get_ssh_argv(config) print "~~~", " ".join(shell_escape(a) for a in ssh_argv) return basebox(config, args)
def get_ssh_argv(config, argv=()): return ["ssh", "-i", config["ssh_key_path"], "-o", "HostKeyAlias=basebox", "-o", "HashKnownHosts=no", "-o", "BatchMode=yes", # "-t", "-o", "ServerAliveInterval=20", "-q", "-o", "UserKnownHostsFile=" + config["host_key_path"] + ".known", "[email protected]"] + [ " ".join(shell_escape(a) for a in argv)]
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)