def exposePort(self, local_port, public_port, scheme): keyfile = self.core.getInsecureKeyFile() keyfile = inner(keyfile) forward_descr = "0.0.0.0:%s:127.0.0.1:%s" % (public_port, local_port) engineIP = self.getSSHIP() enginePort = str(self.getSSHPort()) cmdPath = "ssh" cmdArgs = [ "ssh", "-N", "-L", forward_descr, engineIP, "-l", "substance", "-p", enginePort, "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", "-i", keyfile ] sudo = False if public_port < 1024 and not isWithinWindowsSubsystem(): sudo = True self.logAdapter.info( "Exposing port %s as %s; kill the process (CTRL-C) to un-expose.", local_port, public_port) with closing(socket.socket(socket.AF_INET, socket.SOCK_DGRAM)) as s: s.connect(("8.8.8.8", 80)) ip = s.getsockname()[0] if scheme: self.logAdapter.info("%s://%s:%s is now available.", scheme, ip, public_port) else: self.logAdapter.info( "Others can now connect to port %s via IP %s.", public_port, ip) Shell.execvp(cmdPath, cmdArgs, {}, sudo=sudo)
def tearDownClass(cls): if cls.engine and cls.engine.isProvisioned(): cls.engine.deprovision() if cls.basePath: Shell.nukeDirectory(cls.basePath).catch(cls.raiser) if cls.projectsPath: Shell.nukeDirectory(cls.projectsPath).catch(cls.raiser)
def tearDownClass(cls): if cls.vmUUID: machine.terminate(cls.vmUUID) machine.delete(cls.vmUUID) if cls.basePath: Shell.nukeDirectory(cls.basePath).catch(cls.raiser) if cls.projectsPath: Shell.nukeDirectory(cls.projectsPath).catch(cls.raiser)
def remove(self): if not os.path.isdir(self.enginePath): return Fail( FileSystemError("Engine \"%s\" does not exist." % self.name)) if self.isProvisioned(): return Fail( EngineProvisioned("Engine \"%s\" is provisioned." % self.name)) return Shell.nukeDirectory(self.enginePath)
def importOVF(importParams, name, ovfFile): ''' Import the OVF file as a virtual box vm. ''' ovfFile = Shell.normalizePath(ovfFile) importParams.insert(0, '"' + ovfFile + '"') return vboxManager("import", " ".join(importParams)) \ .then(defer(readMachineID, name))
def getUnisonArgs(self, direction, path=''): folder = self.engine.getEngineFolders()[0] localRoot = Shell.normalizePath(os.path.join(folder.hostPath, path)) remoteRoot = 'ssh://substance@%s/%s/%s' % ( self.engine.getSSHIP(), folder.guestPath.rstrip('/'), path.lstrip('/')) # Direction arguments if direction == Syncher.UP: directionArgs = [ '-nocreation', localRoot, '-nodeletion', localRoot, '-noupdate', localRoot ] elif direction == Syncher.DOWN: directionArgs = [ '-nocreation', remoteRoot, '-nodeletion', remoteRoot, '-noupdate', remoteRoot ] else: directionArgs = ['-prefer', 'newer', '-copyonconflict'] # User args userArgs = folder.syncArgs # Other arguments rootArgs = [localRoot, remoteRoot] ignoreArgs = [ item for sublist in [['-ignore', 'Name ' + excl] for excl in folder.excludes] for item in sublist ] # SSH config transport = "-p %s -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" % self.engine.getSSHPort( ) if self.keyfile is not None: transport += " -i %s" % Shell.normalizePath(self.keyfile) # Assemble everything args = ['-batch', '-repeat', 'watch', '-sshargs', transport] + \ userArgs + directionArgs + ignoreArgs + rootArgs if self.ignoreArchives and '-ignorearchives' not in args: args.insert(0, '-ignorearchives') return args
def create(self, config=None, profile=None): if os.path.isdir(self.enginePath): return Fail(EngineExistsError("Engine \"%s\" already exists." % self.name)) return Shell.makeDirectory(self.enginePath) \ .then(defer(self.makeDefaultConfig, config=config, profile=profile)) \ .bind(self.__ensureDevroot) \ .bind(self.validateConfig) \ .then(self.config.saveConfig) \ .bind(dinfo("Generated default engine configuration in %s", self.config.configFile)) \ .map(self.chainSelf)
def start(self, direction, path=''): self.ensureKeyPerms() unisonPath = self.getUnisonBin() unisonArgs = self.getUnisonArgs(direction, path) unisonEnv = self.getUnisonEnv() if self.ignoreArchives: # It seems that in certain cases, unison does not observe the -ignorearchives flag correctly # So to make sure, we forcibly delete previous archives on both sides res = Try.sequence([ # Delete host archives Shell.call(["rm", "-rf", unisonEnv['UNISON']], shell=False), # Delete guest archives self.engine.readLink().bind(Link.runCommand, 'rm -rf /substance/.unison') ]) if res.isFail(): return res logger.info("Syncing local directory %s to remote directory %s", unisonArgs[-2], unisonArgs[-1]) logger.debug("EXEC: %s", Shell.stringify([unisonPath] + unisonArgs, unisonEnv)) os.execve(unisonPath, unisonArgs, unisonEnv)
def getUnisonEnv(self): # Add the unison-fsmonitor binary to PATH path = self.getUnisonSupportDirectory() + os.pathsep + os.environ.get( 'PATH', '') # Tell unison to save all replica state to ~/.substance/unison unisonDir = Shell.normalizePath( os.path.join(self.engine.core.getBasePath(), 'unison')) homeDir = os.environ.get('HOME', os.path.expanduser('~')) return { 'UNISON': unisonDir, 'PATH': path, 'HOME': homeDir, 'SSH_AUTH_SOCK': os.environ.get('SSH_AUTH_SOCK', '') }
def download(self, boxResult): archiveURL = boxResult['archiveURL'] archiveSHA = boxResult['archiveSHA1'] archive = self.getArchivePath() logger.info("Downloading %s:%s (%s)", self.name, self.version, boxResult['archiveURL']) return Try.sequence([ Shell.makeDirectory(os.path.dirname(archive)), Try.attempt(streamDownload, url=archiveURL, destination=archive) .then(defer(self.verifyArchive, expectedSHA=archiveSHA)) .then(defer(self.unpackArchive)), self.core.getDB().updateBoxRecord(self, boxResult) ]).map(lambda x: self)
def unpackArchive(self): return Try.sequence([ Try.attempt(untar, self.getArchivePath(), self.getPath()), Shell.rmFile(self.getArchivePath()) ])
def __ensureDevroot(self, config): devroot = os.path.expanduser(config.get('devroot', {}).get('path')) if not os.path.isdir(devroot): self.logAdapter.info("Creating devroot at %s" % devroot) return Shell.makeDirectory(devroot).then(lambda: OK(config)) return OK(config)
def sync(self): op = Shell.call(self.getCommand()) if op.isFail(): print("%s" % op) return op return OK(self)
def tearDown(self): if self.basePath: Shell.nukeDirectory(self.basePath).catch(TestCore.raiser) if self.projectsPath: Shell.nukeDirectory(self.projectsPath).catch(TestCore.raiser)
def vboxExec(cmd, params=""): return Shell.procCommand("%s %s %s" % ("VBoxManage", cmd, params)) \ .bind(onVboxCommand) \ .catch(onVboxError)
def commitToSystem(self): hostsPath = self.determine_hosts_path() logger.debug("Commiting '%s' to system '%s'" % (self.hosts_path, hostsPath)) return Shell.call(["cp", self.hosts_path, self.determine_hosts_path()], shell=False, sudo=True) \ .then(lambda: os.remove(self.tempFile.name))
def delete(self): logger.info("Removing box %s from box cache", self.getShortBoxString()) return Try.sequence([ self.core.getDB().removeBoxRecord(self), Shell.nukeDirectory(self.getPath()) ])
def inspectOVF(ovfFile): ''' Inspect an OVF file to extract it's examined output ''' return vboxManager("import", '-n "%s"' % Shell.normalizePath(ovfFile))