def forward(self, port): # Forward a port from a local host to the VM. local_port = port + 10000 debug("forwarding: localhost:{} -> {}:{}", local_port, self.name, port) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect(('127.0.0.1', local_port)) sock.close() is_taken = True except socket.error: is_taken = False port_path = CTL_DIR + "/port.%s" % port if is_taken: if os.path.exists(port_path): name = open(port_path).read().strip() if name != self.name: vm = VM.find(name) if not vm.running(): raise fail("unable to forward port: {} -> {}:{}", local_port, self.name, port) raise fail( "unable to forward port: {} -> {}:{}" " (already forwarded by VM {})", local_port, self.name, port, name) else: raise fail("unable to forward port: {} -> {}:{}", local_port, self.name, port) else: self.ctl("hostfwd_add tcp:127.0.0.1:%s-:%s" % (local_port, port)) open(port_path, 'w').write("%s\n" % self.name)
def unforward(self, port): # Remove a forwarding rule. local_port = port + 10000 debug("unforwarding: localhost:{} -> {}:{}", local_port, self.name, port) self.ctl("hostfwd_remove tcp:127.0.0.1:%s-:%s" % (local_port, port)) port_path = CTL_DIR + "/port.%s" % port if os.path.exists(port_path): rm(port_path)
def ctl(self, command): # Send a command to the VM. sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(self.ctl_path) time.sleep(0.1) sock.recv(4096) for line in command.splitlines(): debug("writing: {} << {}", self.ctl_path, line) sock.send(command + "\n") time.sleep(0.1) data = sock.recv(4096) for line in data.splitlines(): debug("reading: {} >> {}", self.ctl_path, line) sock.close()
def download(self, urls): # Download a file from a list of URLs and save it to `./vm/tmp`. for url in urls: path = TMP_DIR + "/" + os.path.basename(url) if os.path.exists(path): return path data = None debug("downloading: {} => {}", url, path) try: data = urllib2.urlopen(url).read() except urllib2.HTTPError: pass if data is not None: stream = open(path, 'w') stream.write(data) stream.close() return path raise fail("failed to download: {}", ", ".join(urls))
def build(self): # Generate a VM image. if not self.missing(): raise fail("VM is already built") for path in [IMG_DIR, CTL_DIR, TMP_DIR]: if not os.path.exists(path): mktree(path) identity_path = CTL_DIR + "/identity" if not os.path.exists(identity_path): sh("ssh-keygen -q -N \"\" -f %s" % identity_path) config_path = CTL_DIR + "/ssh_config" if not os.path.exists(config_path): config_template_path = DATA_ROOT + "/vm/ssh_config" config_template = open(config_template_path).read() config = config_template.replace("$VM_ROOT", VM_ROOT) assert config != config_template debug("translating: {} => {}", config_template_path, config_path) open(config_path, 'w').write(config)
def unpack_iso(self, iso_path, target_path): # Unpack an ISO image. assert os.path.isfile(iso_path) if not os.path.exists(target_path): mktree(target_path) debug("unpacking: {} => {}", iso_path, target_path) listing = pipe("isoinfo -i %s -R -f" % iso_path) for entry in listing.splitlines(): filename = target_path + entry dirname = os.path.dirname(filename) if not os.path.exists(dirname): mktree(dirname) with env(debug=False): content = pipe("isoinfo -i %s -R -x '%s'" % (iso_path, entry)) if not content: continue #debug("extracting: {} => {}", entry, filename) stream = open(filename, 'w') stream.write(content) stream.close()
def trial(command, description): # Run a command on VM; complain if exited with non-zero error code. log("{}...", description) command = "ssh -F %s linux-vm \"cd src/htsql && %s\"" \ % (CTL_DIR+"/ssh_config", command) stream = subprocess.PIPE debug("trying: {}", command) proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out, err = proc.communicate() if proc.returncode == 0: log("{}: PASSED", description) return 0 out = out.strip() log("{}: :warning:`FAILED!`", description) log("*" * 72) sys.stdout.write(out + "\n") log("*" * 72) return 1
def build(self): super(WindowsTemplateVM, self).build() log("building VM: `{}`...", self.name) start_time = datetime.datetime.now() src_iso_path = env.windows_iso if not (src_iso_path and os.path.isfile(src_iso_path)): src_iso_path = None output = pipe("locate %s || true" % " ".join(WINDOWS_ISO_FILES)) for line in output.splitlines(): if os.path.exists(line): src_iso_path = line break if src_iso_path is None: log("unable to find an ISO image for Windows XP or Windows 2003") src_iso_path = prompt("enter path to an ISO image:") if not (src_iso_path and os.path.isfile(src_iso_path)): raise fail("invalid path: %s" % src_iso_path) key_regexp = re.compile(r'^\w{5}-\w{5}-\w{5}-\w{5}-\w{5}$') key = env.windows_key if not (key and key_regexp.match(key)): key = None key_path = os.path.splitext(src_iso_path)[0] + ".key" if os.path.isfile(key_path): key = open(key_path).readline().strip() if not key_regexp.match(key): key = None if key is None: log("unable to find a Windows product key") key = prompt("enter product key:") if not key_regexp.match(key): raise fail("invalid product key: {}", key) wget_path = self.download(WGET_EXE_URLS) unpack_path = TMP_DIR + "/" + self.name boot_path = unpack_path + "/eltorito.img" if os.path.exists(unpack_path): rmtree(unpack_path) self.unpack_iso(src_iso_path, unpack_path) self.unpack_iso_boot(src_iso_path, boot_path) sif_template_path = DATA_ROOT + "/vm/%s-winnt.sif" % self.name sif_path = unpack_path + "/I386/WINNT.SIF" debug("translating: {} => {}", sif_template_path, sif_path) sif_template = open(sif_template_path).read() sif = sif_template.replace("#####-#####-#####-#####-#####", key) assert sif != sif_template open(sif_path, 'w').write(sif) install_path = unpack_path + "/$OEM$/$1/INSTALL" mktree(install_path) cp(wget_path, install_path) cp(CTL_DIR + "/identity.pub", install_path) cp(DATA_ROOT + "/vm/%s-install.cmd" % self.name, install_path + "/INSTALL.CMD") iso_path = TMP_DIR + "/%s.iso" % self.name if os.path.exists(iso_path): rm(iso_path) sh("mkisofs -o %s -q -iso-level 2 -J -l -D -N" " -joliet-long -relaxed-filenames -no-emul-boot" " -boot-load-size 4 -b eltorito.img %s" % (iso_path, unpack_path)) rmtree(unpack_path) try: self.kvm_img() self.kvm("-cdrom %s -boot d" % iso_path) rm(iso_path) self.compress() except: if os.path.exists(self.img_path): rm(self.img_path) raise stop_time = datetime.datetime.now() log("VM is built successfully: `{}` ({})", self.name, stop_time - start_time)
def unpack_iso_boot(self, iso_path, boot_path): # Unpack El Torito boot image from and ISO. assert os.path.isfile(iso_path) debug("unpacking boot image: {} => {}", iso_path, boot_path) sh("geteltorito -o %s %s" % (boot_path, iso_path))