def yumRemove(self, package, dryRun): sh = shellRunner() if dryRun=='true': script = [ 'rpm', '-e', '--test', package ] else: script = [ 'yum', 'erase', '-y', package ] return sh.run(script)
def yumInstall(self, package, dryRun): sh = shellRunner() if dryRun=='true': script = [ 'yum', 'install', '-y', '--downloadonly', package ] else: script = [ 'yum', 'install', '-y', package ] return sh.run(script)
def put(self, response): if 'actions' in response: actions = response['actions'] logger.debug(actions) # for the servers, take a diff of what's running, and what the controller # asked the agent to start. Kill all those servers that the controller # didn't ask us to start sh = shellRunner() runningServers = sh.getServerTracker() # get the list of servers the controller wants running serversToRun = {} for action in actions: if action['kind'] == 'START_ACTION': processKey = sh.getServerKey(action['clusterId'],action['clusterDefinitionRevision'], action['component'], action['role']) serversToRun[processKey] = 1 # create stop actions for the servers that the controller wants stopped for server in runningServers.keys(): if server not in serversToRun: sh.stopProcess(server) # now put all the actions in the queue. The ordering is important (we stopped # all unneeded servers first) for action in actions: q.put(action)
def setUp(self): self.tmpdir = tempfile.mkdtemp() self.tmpdict = tempfile.NamedTemporaryFile(dir=self.tmpdir) self.tmpdict = open(self.tmpdir + os.sep + MAPPING_FILE_NAME, 'w') self.sh = shellRunner() #Launch eternal process p = subprocess.Popen([COMPONENT_LIVE_CMD], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, close_fds=True) #Write mapping for pid files for both live and dead process self.tmpdict.write(COMPONENT_LIVE + '=' + COMPONENT_LIVE_PID + os.linesep) self.tmpdict.write(COMPONENT_DEAD + '=' + COMPONENT_DEAD_PID + os.linesep) self.tmpdict.close() #Write pid of live process to file live_pid_file = open(self.tmpdir + os.sep + COMPONENT_LIVE_PID, 'w') self.live_pid = p.pid live_pid_file.write(str(self.live_pid)) live_pid_file.close() #Write pid of dead process to file dead_pid_file = open(self.tmpdir + os.sep + COMPONENT_DEAD_PID, 'w') dead_pid_file.write(str(DEAD_PID)) dead_pid_file.close() #Init status checker self.statusCheck = StatusCheck(self.tmpdir, self.tmpdict.name)
def __init__(self, serviceToPidDict, pidPathesVars, globalConfig, servicesToLinuxUser): self.serToPidDict = serviceToPidDict.copy() self.pidPathesVars = pidPathesVars self.pidPathes = [] self.sh = shellRunner() self.pidFilesDict = {} self.globalConfig = globalConfig self.servicesToLinuxUser = servicesToLinuxUser self.fillDirValues() for pidPath in self.pidPathes: self.listFiles(pidPath) for service, pid in self.serToPidDict.items(): if self.servicesToLinuxUser.has_key(service): linuxUserKey = self.servicesToLinuxUser[service] if self.globalConfig.has_key(linuxUserKey): self.serToPidDict[service] = string.replace(pid, self.USER_PATTERN, self.globalConfig[linuxUserKey]) else: if self.USER_PATTERN in pid: logger.error('There is no linux user mapping for component: ' + service) if StatusCheck.firstInit: logger.info('Service to pid dictionary: ' + str(self.serToPidDict)) StatusCheck.firstInit = False else: logger.debug('Service to pid dictionary: ' + str(self.serToPidDict))
def yumInstall(self, package, dryRun): sh = shellRunner() if dryRun == 'true': script = ['yum', 'install', '-y', '--downloadonly', package] else: script = ['yum', 'install', '-y', package] return sh.run(script)
def yumRemove(self, package, dryRun): sh = shellRunner() if dryRun == 'true': script = ['rpm', '-e', '--test', package] else: script = ['yum', 'erase', '-y', package] return sh.run(script)
def tarballRemove(self, package, dryRun): sh = shellRunner() package = os.path.basename(package) if string.find(package, '.tgz') != -1: package = package[:-4] elif string.find(package, '.tar.gz') != -1: package = package[:-7] src = packageRunner.softwarePrefix + '/' + package try: if dryRun != 'true': shutil.rmtree(src) else: if os.path.exists(src) != True: err = packageRunner.softwarePrefix + '/' + package + ' does not exist.' raise Exception(err) result = { 'exit_code': 0, 'output': package + ' deleted', 'error': '' } except Exception, err: result = { 'exit_code': 1, 'output': 'Error in deleting ' + package, 'error': str(err) }
def __init__(self, parsedJson, path, modulesdir, taskId, config): self.parsedJson = parsedJson self.path = path self.modulesdir = modulesdir self.taskId = taskId self.sh = shellRunner() self.config = config
def __init__(self, serviceToPidDict, pidPathesVars, globalConfig, servicesToLinuxUser): self.serToPidDict = serviceToPidDict self.pidPathesVars = pidPathesVars self.pidPathes = [] self.sh = shellRunner() self.pidFilesDict = {} self.globalConfig = globalConfig self.servicesToLinuxUser = servicesToLinuxUser self.fillDirValues() for pidPath in self.pidPathes: self.listFiles(pidPath) for service, pid in self.serToPidDict.items(): if self.servicesToLinuxUser.has_key(service): linuxUserKey = self.servicesToLinuxUser[service] if self.globalConfig.has_key(linuxUserKey): self.serToPidDict[service] = string.replace(pid, self.USER_PATTERN, self.globalConfig[linuxUserKey]) else: if self.USER_PATTERN in pid: logger.error('There is no linux user mapping for component: ' + service) if StatusCheck.firstInit: logger.info('Service to pid dictionary: ' + str(self.serToPidDict)) StatusCheck.firstInit = False else: logger.debug('Service to pid dictionary: ' + str(self.serToPidDict))
def __init__(self, puppetModule, puppetInstall, facterInstall, tmpDir, config): self.puppetModule = puppetModule self.puppetInstall = puppetInstall self.facterInstall = facterInstall self.tmpDir = tmpDir self.reposInstalled = False self.config = config self.modulesdir = self.puppetModule + "/modules" self.sh = shellRunner()
def __init__(self, config): global clusterId, clusterDefinitionRevision super(ActionQueue, self).__init__() #threading.Thread.__init__(self) self.config = config self.sh = shellRunner() self._stop = threading.Event() self.maxRetries = config.getint('command', 'maxretries') self.sleepInterval = config.getint('command', 'sleepBetweenRetries')
def ethtool(self): sh = shellRunner() script = ["ethtool", "eth0", "|", "grep", "Speed:", "|", "sed", "'s/\s*Speed:\s*//'", "|", "sed", "'s/Mb\/s//'"] result = sh.run(script) if "ethtool: not found\n" in result["error"]: # ethtool not installed, assume a speed of 0Mb/s self.netSpeed = 0 else: self.netSpeed = int(result["output"].rstrip())
def torrentDownload(self, package): sh = shellRunner() startTime = time.time() script = [ 'transmission-daemon', '-y', '-O', '-M', '-w', packageRunner.downloadDir, '-g', packageRunner.hmsPrefix + '/var/cache/config' ] result = sh.run(script) for wait in [1, 1, 2, 2, 5]: script = ['transmission-remote', '-l'] result = sh.run(script) if result['exit_code'] == 0: break time.sleep(wait) if result['exit_code'] != 0: raise Exception('Unable to start transmission-daemon, exit_code:' + str(result['exit_code'])) script = [ 'transmission-remote', '-a', package, '--torrent-done-script', '/usr/bin/hms-torrent-callback' ] result = sh.run(script) if result['exit_code'] != 0: raise Exception('Unable to issue transmission-remote command') trackerComplete = packageRunner.hmsPrefix + '/var/tmp/tracker' while True: if os.path.exists(trackerComplete): break script = ['transmission-remote', '-t', '1', '--reannounce'] sh.run(script) time.sleep(5) endTime = time.time() duration = endTime - startTime os.remove(trackerComplete) code = 0 script = ['transmission-remote', '-t', '1', '-r'] result = sh.run(script) if result['exit_code'] != 0: code = result['exit_code'] logger.warn('Can not remove torrent, output: ' + result['output'] + ' error: ' + result['error']) script = ['transmission-remote', '--exit'] result = sh.run(script) if result['exit_code'] != 0: code = result['exit_code'] logger.warn('Can not shutdown torrent client, output: ' + result['output'] + ' error: ' + result['error']) output = "%s downloaded duration: %d seconds." % (package, duration) while True: """ Make sure transmission-daemon is properly terminated """ script = ['transmission-remote', '-l'] result = sh.run(script) if result['exit_code'] != 0: break return {'exit_code': code, 'output': output, 'error': ''}
def test_shellRunner_run(self, getpwnamMock): sh = shellRunner() result = sh.run(['echo']) self.assertEquals(result['exitCode'], 0) self.assertEquals(result['error'], '') getpwnamMock.return_value = [os.getuid(), os.getuid(), os.getuid()] result = sh.run(['echo'], 'non_exist_user_name') self.assertEquals(result['exitCode'], 0) self.assertEquals(result['error'], '')
def __init__(self, config, controller): super(ActionQueue, self).__init__() self.commandQueue = Queue.Queue() self.commandStatuses = CommandStatusDict( callback_action=self.status_update_callback) self.config = config self.controller = controller self.sh = shellRunner() self._stop = threading.Event() self.tmpdir = config.get('agent', 'prefix')
def __init__(self, puppetModule, puppetInstall, facterInstall, tmpDir, config): self.puppetModule = puppetModule self.puppetInstall = puppetInstall self.facterInstall = facterInstall self.tmpDir = tmpDir self.reposInstalled = False self.config = config self.modulesdir = self.puppetModule + "/modules" self.event = threading.Event() self.last_puppet_has_been_killed = False self.sh = shellRunner() self.puppet_timeout = config.get("puppet", "timeout_seconds")
def __init__(self, config, controller): super(ActionQueue, self).__init__() self.commandQueue = Queue.Queue() self.commandStatuses = CommandStatusDict(callback_action= self.status_update_callback) self.config = config self.controller = controller self.sh = shellRunner() self._stop = threading.Event() self.tmpdir = config.getResolvedPath(AgentConfig.APP_TASK_DIR) self.customServiceOrchestrator = CustomServiceOrchestrator(config, controller)
def __init__(self, config, controller): super(ActionQueue, self).__init__() self.commandQueue = Queue.Queue() self.commandStatuses = CommandStatusDict( callback_action=self.status_update_callback) self.config = config self.controller = controller self.sh = shellRunner() self._stop = threading.Event() self.tmpdir = config.getResolvedPath(AgentConfig.APP_TASK_DIR) self.customServiceOrchestrator = CustomServiceOrchestrator( config, controller)
def __init__(self, config): super(ActionQueue, self).__init__() #threading.Thread.__init__(self) self.config = config self.sh = shellRunner() self._stop = threading.Event() self.maxRetries = config.getint('command', 'maxretries') self.sleepInterval = config.getint('command', 'sleepBetweenRetries') self.executor = puppetExecutor.puppetExecutor( config.get('puppet', 'puppetmodules'), config.get('puppet', 'puppet_home'), config.get('puppet', 'facter_home'), config.get('agent', 'prefix'))
def __init__(self, config, controller): super(ActionQueue, self).__init__() self.commandQueue = Queue.Queue() self.statusCommandQueue = Queue.Queue() self.backgroundCommandQueue = Queue.Queue() self.commandStatuses = CommandStatusDict(callback_action = self.status_update_callback) self.config = config self.controller = controller self.sh = shellRunner() self.configTags = {} self._stop = threading.Event() self.tmpdir = config.get('agent', 'prefix') self.customServiceOrchestrator = CustomServiceOrchestrator(config, controller)
def __init__(self, path, mappingFilePath): if not os.path.isdir(path): raise ValueError("Path argument must be valid directory") if not os.path.exists(mappingFilePath): raise IOError("File with services to pid mapping doesn't exists") self.path = path self.mappingFilePath = mappingFilePath self.sh = shellRunner() self.pidFilesDict = {} self.listFiles(self.path) with open(self.mappingFilePath) as fd: self.serToPidDict = dict(self.get_pair(line) for line in fd)
def build(self): sh = shellRunner() list = [] servers = sh.getServerTracker() for server in servers: (clusterId, clusterDefinitionRevision, component, role) = server.split("/") result = { 'clusterId' : clusterId, 'clusterDefinitionRevision' : clusterDefinitionRevision, 'componentName' : component, 'roleName' : role, 'serverStatus' : 'STARTED' } list.append(result) return list
def __init__(self, config, controller): super(ActionQueue, self).__init__() self.commandQueue = Queue.Queue() self.statusCommandQueue = Queue.Queue() self.backgroundCommandQueue = Queue.Queue() self.commandStatuses = CommandStatusDict( callback_action=self.status_update_callback) self.config = config self.controller = controller self.sh = shellRunner() self.configTags = {} self._stop = threading.Event() self.tmpdir = config.get('agent', 'prefix') self.customServiceOrchestrator = CustomServiceOrchestrator( config, controller)
def torrentDownload(self, package): sh = shellRunner() startTime = time.time() script = ['transmission-daemon', '-y', '-O', '-M', '-w', packageRunner.downloadDir, '-g', packageRunner.hmsPrefix+'/var/cache/config'] result = sh.run(script) for wait in [ 1, 1, 2, 2, 5 ]: script = ['transmission-remote', '-l'] result = sh.run(script) if result['exit_code']==0: break time.sleep(wait) if result['exit_code']!=0: raise Exception('Unable to start transmission-daemon, exit_code:'+str(result['exit_code'])) script = ['transmission-remote', '-a', package, '--torrent-done-script', '/usr/bin/hms-torrent-callback'] result = sh.run(script) if result['exit_code']!=0: raise Exception('Unable to issue transmission-remote command') trackerComplete = packageRunner.hmsPrefix+'/var/tmp/tracker' while True: if os.path.exists(trackerComplete): break script = ['transmission-remote', '-t', '1', '--reannounce'] sh.run(script) time.sleep(5) endTime = time.time() duration = endTime - startTime os.remove(trackerComplete) code = 0 script = [ 'transmission-remote', '-t', '1', '-r' ] result = sh.run(script) if result['exit_code']!=0: code = result['exit_code'] logger.warn('Can not remove torrent, output: '+result['output']+' error: '+result['error']) script = [ 'transmission-remote', '--exit' ] result = sh.run(script) if result['exit_code']!=0: code = result['exit_code'] logger.warn('Can not shutdown torrent client, output: '+result['output']+' error: '+result['error']) output = "%s downloaded duration: %d seconds." % (package, duration) while True: """ Make sure transmission-daemon is properly terminated """ script = [ 'transmission-remote', '-l' ] result = sh.run(script) if result['exit_code']!=0: break return {'exit_code': code, 'output': output, 'error': ''}
def __init__(self, config): super(ActionQueue, self).__init__() self.config = config self.sh = shellRunner() self._stop = threading.Event() self.maxRetries = config.getint('command', 'maxretries') self.sleepInterval = config.getint('command', 'sleepBetweenRetries') self.puppetExecutor = PuppetExecutor.PuppetExecutor( config.get('puppet', 'puppetmodules'), config.get('puppet', 'puppet_home'), config.get('puppet', 'facter_home'), config.get('agent', 'prefix'), config) self.pythonExecutor = PythonExecutor.PythonExecutor( config.get('agent', 'prefix'), config) self.upgradeExecutor = UpgradeExecutor.UpgradeExecutor(self.pythonExecutor, self.puppetExecutor, config) self.tmpdir = config.get('agent', 'prefix') self.commandInProgress = None
def __init__(self, config): super(ActionQueue, self).__init__() self.config = config self.sh = shellRunner() self._stop = threading.Event() self.maxRetries = config.getint('command', 'maxretries') self.sleepInterval = config.getint('command', 'sleepBetweenRetries') self.puppetExecutor = PuppetExecutor.PuppetExecutor( config.get('puppet', 'puppetmodules'), config.get('puppet', 'puppet_home'), config.get('puppet', 'facter_home'), config.get('agent', 'prefix'), config) self.pythonExecutor = PythonExecutor.PythonExecutor( config.get('agent', 'prefix'), config) self.upgradeExecutor = UpgradeExecutor.UpgradeExecutor( self.pythonExecutor, self.puppetExecutor, config) self.tmpdir = config.get('agent', 'prefix') self.commandInProgress = None
def tarballRemove(self, package, dryRun): sh = shellRunner() package = os.path.basename(package) if string.find(package, '.tgz')!=-1: package = package[:-4] elif string.find(package, '.tar.gz')!=-1: package = package[:-7] src = packageRunner.softwarePrefix+'/'+package try: if dryRun!='true': shutil.rmtree(src) else: if os.path.exists(src)!=True: err = packageRunner.softwarePrefix+'/'+package+' does not exist.' raise Exception(err) result = {'exit_code': 0, 'output': package+' deleted', 'error': ''} except Exception, err: result = {'exit_code': 1, 'output': 'Error in deleting '+package, 'error': str(err)}
def __init__(self, serviceToPidDict, pidPathesVars, globalConfig, linuxUserPattern): self.serToPidDict = serviceToPidDict self.pidPathesVars = pidPathesVars self.pidPathes = [] self.sh = shellRunner() self.pidFilesDict = {} self.globalConfig = globalConfig self.linuxUserPattern = linuxUserPattern self.fillDirValues() for pidPath in self.pidPathes: self.listFiles(pidPath) for service, pid in self.serToPidDict.items(): self.serToPidDict[service] = string.replace( pid, '{USER}', self.linuxUserPattern)
def tarballInstall(self, package): sh = shellRunner() src = packageRunner.hmsPrefix+'/var/cache/downloads/'+package script = [ 'tar', 'fxz', src, '-C', packageRunner.softwarePrefix ] result = sh.run(script) if result['exit_code']!=0: err = 'Tarball decompress error, exit code: %d' % result['exit_code'] raise Exception(err) # script = [ packageRunner.hmsPrefix+'/var/repos/'+package+'/preinstall' ] # result = sh.run(script) # if result['exit_code']!=0: # err = 'Preinstall script exit code: %d' % result['exit_code'] # raise Exception(err) # script = [ 'tar', 'fxz', package, '-C', softwarePrefix ] # result = sh.run(script) # if result['exit_code']!=0: # err = 'Tarball decompress error, exit code: %d' % result['exit_code'] # raise Exception(err) # script = [ packageRunner.hmsPrefix+'/var/repos'+package+'/postinstall' ] return result
def run(self, data): Runner.lock.acquire() try: if data['actionType'] == 'info': ph = packageRunner() result = ph.info(data['packages']) elif data['actionType'] == 'install': ph = packageRunner() if 'dry-run' in data: opt = data['dry-run'] else: opt = 'false' result = ph.install(data['packages'], opt) elif data['actionType'] == 'remove': ph = packageRunner() if 'dry-run' in data: opt = data['dry-run'] else: opt = 'false' result = ph.remove(data['packages'], opt) elif data['actionType'] == 'status': dh = daemonRunner() result = dh.status(data['daemonName']) elif data['actionType'] == 'start': dh = daemonRunner() result = dh.start(data['daemonName']) elif data['actionType'] == 'stop': dh = daemonRunner() result = dh.stop(data['daemonName']) elif data['actionType'] == 'run' or data[ '@action'] == 'org.apache.hms.common.entity.action.ScriptAction': she = shellRunner() script = [] script.append(data['script']) if "parameters" in data: for parameter in data['parameters']: script.append(parameter) result = she.run(script) return result finally: Runner.lock.release()
def tarballInstall(self, package): sh = shellRunner() src = packageRunner.hmsPrefix + '/var/cache/downloads/' + package script = ['tar', 'fxz', src, '-C', packageRunner.softwarePrefix] result = sh.run(script) if result['exit_code'] != 0: err = 'Tarball decompress error, exit code: %d' % result[ 'exit_code'] raise Exception(err) # script = [ packageRunner.hmsPrefix+'/var/repos/'+package+'/preinstall' ] # result = sh.run(script) # if result['exit_code']!=0: # err = 'Preinstall script exit code: %d' % result['exit_code'] # raise Exception(err) # script = [ 'tar', 'fxz', package, '-C', softwarePrefix ] # result = sh.run(script) # if result['exit_code']!=0: # err = 'Tarball decompress error, exit code: %d' % result['exit_code'] # raise Exception(err) # script = [ packageRunner.hmsPrefix+'/var/repos'+package+'/postinstall' ] return result
def run(self, data): Runner.lock.acquire() try: if data['actionType']=='info': ph = packageRunner() result = ph.info(data['packages']) elif data['actionType']=='install': ph = packageRunner() if 'dry-run' in data: opt = data['dry-run'] else: opt = 'false' result = ph.install(data['packages'], opt) elif data['actionType']=='remove': ph = packageRunner() if 'dry-run' in data: opt = data['dry-run'] else: opt = 'false' result = ph.remove(data['packages'], opt) elif data['actionType']=='status': dh = daemonRunner() result = dh.status(data['daemonName']) elif data['actionType']=='start': dh = daemonRunner() result = dh.start(data['daemonName']) elif data['actionType']=='stop': dh = daemonRunner() result = dh.stop(data['daemonName']) elif data['actionType']=='run' or data['@action']=='org.apache.hms.common.entity.action.ScriptAction': she = shellRunner() script = [] script.append(data['script']) if "parameters" in data: for parameter in data['parameters']: script.append(parameter) result = she.run(script) return result finally: Runner.lock.release()
def ifconfig(self): sh = shellRunner() script = [ "ifconfig", "en0", "|", "grep", "media:", "|", "sed", "'s/.*(//'", "|", "sed", "'s/ .*//'", "|", "sed", "'s/baseT//'", ] result = sh.run(script) if "none" in result["output"]: # No ethernet detected, detect airport script = [ "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport", "-I", "|", "grep", "lastTxRate:", "|", "sed", "'s/.*: //'", "|", "sed", "'s/$//'", ] result = sh.run(script) try: self.netSpeed = int(result["output"].rstrip()) except Exception: self.netSpeed = 0
def findAvahi(self, type): address = [] shell = shellRunner() script = [] script.append('/etc/init.d/avahi-daemon') script.append('status') result = shell.run(script) if result['exit_code'] != 0: logger.info('Starting Avahi daemon.') script = [] script.append('/etc/init.d/avahi-daemon') script.append('start') result = shell.run(script) if result['exit_code'] == 0: logger.info('Avahi daemon started.') else: logger.error(result['output']) time.sleep(2) script = [] script.append('avahi-browse') script.append('-t') script.append('-r') script.append(type) result = shell.run(script) list = result['output'].rsplit("\n") ip = "" port = "2181" for line in list: if 'address = ' in line: start = line.find('[') + 1 end = line.find(']') ip = line[start:end] if 'port = ' in line: start = line.find('[') + 1 end = line.find(']') port = line[start:end] address.append(ip + ':' + port) return ",".join(address)
def findAvahi(self, type): address = [] shell = shellRunner() script = [] script.append("/etc/init.d/avahi-daemon") script.append("status") result = shell.run(script) if result["exit_code"] != 0: logger.info("Starting Avahi daemon.") script = [] script.append("/etc/init.d/avahi-daemon") script.append("start") result = shell.run(script) if result["exit_code"] == 0: logger.info("Avahi daemon started.") else: logger.error(result["output"]) time.sleep(2) script = [] script.append("avahi-browse") script.append("-t") script.append("-r") script.append(type) result = shell.run(script) list = result["output"].rsplit("\n") ip = "" port = "2181" for line in list: if "address = " in line: start = line.find("[") + 1 end = line.find("]") ip = line[start:end] if "port = " in line: start = line.find("[") + 1 end = line.find("]") port = line[start:end] address.append(ip + ":" + port) return ",".join(address)
def tarballInfo(self, package): sh = shellRunner() script = [ 'cat', packageRunner.hmsPrefix+'/var/repos/'+package+'/info' ] return sh.run(script)
def tarballInfo(self, package): sh = shellRunner() script = [ 'cat', packageRunner.hmsPrefix + '/var/repos/' + package + '/info' ] return sh.run(script)
def status(self, name): sh = shellRunner() script = [ '/etc/init.d/'+name, 'stop' ] return sh.run(script)
def yumInfo(self, package): sh = shellRunner() script = [ 'yum', 'info', package ] return sh.run(script)
def yumInfo(self, package): sh = shellRunner() script = ['yum', 'info', package] return sh.run(script)
def rpmInstall(self, packages): sh = shellRunner() list = ' '.join([str(x) for x in packages]) script = ['rpm', '-U', '--replacepkgs', list] return sh.run(script)
def status(self, name): sh = shellRunner() script = ['/etc/init.d/' + name, 'stop'] return sh.run(script)