예제 #1
0
def spawn_session(name: str, kubeconfig_location: str, server: libtmux.Server):
    if server.has_session(name):
        return
    else:
        session = server.new_session(name)
        session.set_environment("KUBECONFIG", kubeconfig_location)
        # the new_session will create default window and pane which will not contain KUBECONFIG, add manually
        session.attached_window.attached_pane.send_keys(
            "export KUBECONFIG={}".format(kubeconfig_location))
예제 #2
0
class TMux:
    def __init__(self, session_name=None, configfile=None, sleep_sec=0.0):
        self.session_name = 'tmule'
        self.configfile = configfile
        if self.configfile:
            self.load_config()
            if 'session' in self.config:
                self.session_name = self.config['session']
        else:
            self.config = None
        if session_name:
            self.session_name = session_name
        self.sleep_sec = sleep_sec
        # max number of loops to wait for process to come up
        self.maxCheckLoops = 16
        # time to wait between checks (factor multiplied by loop)
        self.sleepCheckLoop = 1

    def _on_terminate(self, proc):
        info("process {} terminated with exit code {}".format(
            proc, proc.returncode))

    def _terminate(self, pid):
        procs = Process(pid).children(recursive=True)
        for p in procs:
            info("trying to terminate %s" % p)
            p.terminate()
        _, still_alive = wait_procs(procs,
                                    timeout=1,
                                    callback=self._on_terminate)
        for p in still_alive:
            info("killing %s" % p)
            p.kill()

    def _get_children_pids(self, pid):
        return Process(pid).children(recursive=True)

    def var_substitute(self, root):
        if type(root) == dict:
            for d in root:
                root[d] = self.var_substitute(root[d])
        elif type(root) == list:
            for l in range(0, len(root)):
                root[l] = self.var_substitute(root[l])
        elif type(root) == str:
            for vs in self.var_dict:
                root = root.replace('@%s@' % vs, self.var_dict[vs])
        return root

    def load_config(self):
        with open(self.configfile) as data_file:
            self.config = load(data_file, Loader)
            self.var_dict = {
                'TMULE_CONFIG_FILE': abspath(self.configfile),
                'TMULE_CONFIG_DIR': dirname(abspath(self.configfile)),
                'TMULE_SESSION_NAME': self.session_name
            }
            self.config = self.var_substitute(self.config)
            self.known_tags = set([])
            for w in self.config['windows']:
                if 'tags' in w:
                    for t in w['tags']:
                        self.known_tags.add(t)

    def init(self):
        if not self.config:
            error('config file not loaded; call "load_config" first!')
        else:
            self.server = Server()
            if self.server.has_session(self.session_name):
                self.session = self.server.find_where(
                    {"session_name": self.session_name})

                debug('found running session %s on server' % self.session_name)
            else:
                info('starting new session %s on server' % self.session_name)
                self.session = self.server.new_session(
                    session_name=self.session_name)

            for win in self.config['windows']:
                # print win, "***", self.config['windows']
                window = self.session.find_where({"window_name": win['name']})
                if window:
                    debug('window %s already exists' % win['name'])
                else:
                    info('create window %s' % win['name'])
                    window = self.session.new_window(win['name'])
                exist_num_panes = len(window.list_panes())
                while exist_num_panes < len(win['panes']):
                    info('new pane needed in window %s' % win['name'])
                    window.split_window(vertical=1)
                    exist_num_panes = len(window.list_panes())
                window.cmd('select-layout', 'tiled')

    def find_window(self, window_name):
        for win in self.config['windows']:
            if win['name'] == window_name:
                window = self.session.find_where({"window_name": win['name']})
                # window.select_window()
                return win, window

    def send_ctrlc(self, pane):
        datestr = datetime.now().strftime('%c')
        pane.cmd("send-keys", "", "C-c")
        pane.cmd("send-keys", "", "C-c")
        pane.cmd("send-keys", "", "C-c")
        pane.send_keys('# tmux-controller sent Ctrl-C at %s' % datestr,
                       enter=True,
                       suppress_history=True)

    def launch_window(self, window_name, enter=True):
        info('launch %s' % window_name)
        winconf, window = self.find_window(window_name)
        pane_no = 0
        datestr = datetime.now().strftime('%c')
        for cmd in winconf['panes']:
            pane = window.select_pane(
                '%s:%s.%d' % (window.session.name, window_name, pane_no))
            debug('pane: %d -> %s' % (pane_no, pane))
            self.send_ctrlc(pane)
            pane.send_keys('# tmux-controller starts new command %s' % datestr,
                           enter=True,
                           suppress_history=True)
            if 'init_cmd' in self.config:
                pane.send_keys(self.config['init_cmd'],
                               enter=enter,
                               suppress_history=False)
            pane.send_keys(cmd, enter=enter, suppress_history=False)
            pane_no += 1
        winconf['_running'] = True

    def launch_all_windows(self, tags=set([])):
        for winconf in self.config['windows']:
            selected = 'skip' not in winconf or not winconf['skip']
            if selected and tags:
                if 'tags' in winconf:
                    selected = set(winconf['tags']).intersection(tags)
                else:
                    selected = False
            if selected:
                self.launch_window(winconf['name'])
                w = self.sleep_sec
                if 'wait' in winconf:
                    w = float(winconf['wait'])
                if w > 0:
                    info('sleep %f seconds after launch of %s' %
                         (w, winconf['name']))
                    sleep(w)
                if 'check' in winconf:
                    debug('need to run check command')
                    running = False
                    loop = 0
                    check_cmd = '\n'
                    if 'init_cmd' in self.config:
                        check_cmd += self.config['init_cmd'] + '\n'
                    check_cmd += winconf['check']

                    while not running and loop < self.maxCheckLoops:
                        loop += 1
                        sleep(loop * self.sleepCheckLoop)
                        #running = (call(winconf['check'], shell=True) == 0)
                        running = (call(check_cmd,
                                        executable='/bin/bash',
                                        shell=True,
                                        stdout=None,
                                        stdin=None) == 0)
                        info('ran check for %s (loop %d) => %s' %
                             (winconf['name'], loop, running))
                    if loop >= self.maxCheckLoops:
                        error('window %s failed to come up in time, '
                              'not continuing launch.' % winconf['name'])
                        break

    def stop_all_windows(self, tags=set([])):
        for winconf in self.config['windows'][::-1]:
            selected = 'skip' not in winconf or not winconf['skip']
            if selected and tags:
                if 'tags' in winconf:
                    selected = set(winconf['tags']).intersection(tags)
            if selected:
                self.stop_window(winconf['name'])

    def get_children_pids_all_windows(self):
        pids = []
        for winconf in self.config['windows']:
            pids.extend(self.get_children_pids_window(winconf['name']))
        return pids

    def kill_all_windows(self):
        for winconf in self.config['windows'][::-1]:
            try:
                self.kill_window(winconf['name'])
            except Exception as e:
                warning('There was an exception shutting down, '
                        'carrying on regardless: %s' % str(e))
        self.server.kill_session(self.session_name)

    def stop_window(self, window_name):
        info('stop %s' % window_name)
        winconf, window = self.find_window(window_name)
        self._stop_window(winconf, window)

    def __pids_clean_up(self, pids):
        sleep(1)
        for p in pids:
            try:
                self._terminate(p)
            except Exception as e:
                info('exception in termination, can be ignored: %s' % str(e))

    def _stop_window(self, winconf, window):
        pane_no = 0
        for _ in winconf['panes']:
            pane = window.select_pane(
                '%s:%s.%d' % (window.session.name, window.name, pane_no))
            self.send_ctrlc(pane)
            pane_no += 1
        pids = self._get_pids_window(window)
        Thread(target=self.__pids_clean_up, args=(pids, )).start()
        #for p in pids:
        #self._terminate(p)
        winconf['_running'] = False

    def kill_window(self, window_name):
        info('terminate %s' % window_name)
        winconf, window = self.find_window(window_name)
        #                       "-F '#{pane_active} #{pane_pid}")
        self._stop_window(winconf, window)
        pids = self._get_pids_window(window)
        sleep(1)
        Thread(target=self.__pids_clean_up, args=(pids, )).start()
        winconf['_running'] = False

    def list_windows(self):
        return [w['name'] for w in self.config['windows']]

    def get_pids_window(self, window_name):
        winconf, window = self.find_window(window_name)
        return self._get_pids_window(window)

    def _get_pids_window(self, window):
        r = window.cmd('list-panes', "-F #{pane_pid}")
        return [int(p) for p in r.stdout]

    def get_children_pids_window(self, window_name):
        _, window = self.find_window(window_name)
        return self._get_children_pids_window(window)

    def _get_children_pids_window(self, window):
        winpids = self._get_pids_window(window)
        pids = []
        for pid in winpids:
            pids.extend(self._get_children_pids(pid))
        return [p.pid for p in pids]

    def is_running(self, window_name):
        winconf, window = self.find_window(window_name)
        pids = self._get_children_pids_window(window)
        if len(pids) < 1:
            return False
        if 'check' in winconf:
            debug('need to run check command')
            check_cmd = '\n'
            if 'init_cmd' in self.config:
                check_cmd += self.config['init_cmd'] + '\n'
            check_cmd += winconf['check']
            running = (call(check_cmd,
                            executable='/bin/bash',
                            shell=True,
                            stdout=None,
                            stdin=None) == 0)
            return running
        else:
            return True

    def _server(self, port=9999, keepalive=True):
        from .ws_protocol import JsonWSProtocol
        import web
        from web.httpserver import StaticMiddleware, StaticApp

        from autobahn.twisted.websocket import WebSocketServerProtocol, \
            WebSocketServerFactory
        from autobahn.twisted.resource import WebSocketResource, WSGIRootResource

        from twisted.internet import reactor
        from twisted.web.server import Site
        from twisted.web.wsgi import WSGIResource
        from twisted.python import log
        from twisted.web.static import File

        tmux_self = self

        class TMuxWebServer(web.auto_application):
            def __init__(self):

                web.auto_application.__init__(self)

                self._renderer = web.template.render(path.realpath(
                    path.join(path.dirname(__file__), 'www')),
                                                     base="base",
                                                     globals=globals())

                self_app = self

                class Index(self.page):
                    path = '/'

                    def GET(self):
                        tmux_self.load_config()
                        tmux_self.init()
                        ws_uri = '%s://%s%sws' % (
                            'ws' if web.ctx['protocol'] == 'http' else 'wss',
                            web.ctx['host'], web.ctx['fullpath'])
                        return self_app._renderer.index(
                            ws_uri, tmux_self.config, tmux_self.known_tags)

                class Log(self.page):
                    path = '/log'

                    def GET(self):
                        lines = tmux_self.server.cmd('capture-pane', '-p',
                                                     '-C', '-S',
                                                     '-100000').stdout
                        return '\n'.join(lines)

        class TMuxWSProtocol(JsonWSProtocol):
            def __init__(self):
                super(TMuxWSProtocol, self).__init__()

            def on_button(self, payload):
                debug('button pressed: \n%s' % pformat(payload))
                window_name = payload['id']
                cmd = payload['cmd']
                if cmd == 'launch':
                    if window_name == '':
                        tmux_self.launch_all_windows()
                    else:
                        tmux_self.launch_window(window_name)
                elif cmd == 'launch-tag':
                    tmux_self.launch_all_windows(tags={window_name})
                elif cmd == 'stop':
                    if window_name == '':
                        tmux_self.stop_all_windows()
                    else:
                        tmux_self.stop_window(window_name)
                elif cmd == 'stop-tag':
                    tmux_self.stop_all_windows(tags={window_name})
                elif cmd == 'terminate':
                    tmux_self.kill_all_windows()
                    sleep(1)
                    tmux_self.init()

                sleep(1)
                self.sendJSON(self.on_status())

            def on_status(self, payload=None):
                debug('status-requested: ')

                res = {'windows': {}, 'method': 'update_status'}
                for w in tmux_self.config['windows']:
                    res['windows'][w['name']] = tmux_self.is_running(w['name'])

                return res

                # return {'button_outcome': True}

        log.startLogging(sys.stdout)
        wsFactory = WebSocketServerFactory()
        wsFactory.protocol = TMuxWSProtocol
        wsResource = WebSocketResource(wsFactory)
        staticResource = File(
            path.realpath(path.join(path.dirname(__file__), 'www/static')))

        app = TMuxWebServer()

        # create a Twisted Web WSGI resource for our Flask server
        wsgiResource = WSGIResource(reactor, reactor.getThreadPool(),
                                    app.wsgifunc())

        # create a root resource serving everything via WSGI/Flask, but
        # the path "/ws" served by our WebSocket stuff
        rootResource = WSGIRootResource(wsgiResource, {
            b'ws': wsResource,
            b'static': staticResource
        })

        # create a Twisted Web Site and run everything
        site = Site(rootResource)

        reactor.listenTCP(port, site)
        reactor.run()  # kill everything when server dies
        if not keepalive:
            self.kill_all_windows()
예제 #3
0
        raise SystemExit('%s: file does not exist!' % args.elf)

    uae = FSUAE()
    uae.configure(floppy=args.floppy, rom=args.rom, executable=args.executable)

    ser_port = SOCAT('serial')
    ser_port.configure(tcp_port=8000)

    par_port = SOCAT('parallel')
    par_port.configure(tcp_port=8001)

    subprocess.run(['tmux', '-f', TMUX_CONF, '-L', SOCKET, 'start-server'])

    server = Server(config_file=TMUX_CONF, socket_name=SOCKET)

    if server.has_session(SESSION):
        server.kill_session(SESSION)

    session = server.new_session(session_name=SESSION,
                                 attach=False,
                                 window_name=':0',
                                 window_command='sleep 1')

    try:
        uae.start(session)
        ser_port.start(session)
        par_port.start(session)

        session.kill_window(':0')
        session.select_window(args.window or par_port.name)
        session.attach_session()
예제 #4
0
파일: tmule.py 프로젝트: vigneshrajap/TMuLE
class TMux:
    def __init__(self, session_name="tmule", configfile=None):
        if configfile:
            self.load_config(configfile)
        else:
            self.config = None
        self.session_name = session_name

    def _on_terminate(self, proc):
        info("process {} terminated with exit code {}".format(
            proc, proc.returncode))

    def _terminate(self, pid):
        procs = Process(pid).children()
        for p in procs:
            p.terminate()
        gone, still_alive = wait_procs(procs,
                                       timeout=1,
                                       callback=self._on_terminate)
        for p in still_alive:
            p.kill()

    def _get_children_pids(self, pid):
        return Process(pid).children(recursive=True)

    def load_config(self, filename="sample_config.json"):
        with open(filename) as data_file:
            self.config = load(data_file, Loader)

    def init(self):
        if not self.config:
            error('config file not loaded; call "load_config" first!')
        else:
            self.server = Server()
            if self.server.has_session(self.session_name):
                self.session = self.server.find_where(
                    {"session_name": self.session_name})

                info('found running session %s on server' % self.session_name)
            else:
                info('starting new session %s on server' % self.session_name)
                self.session = self.server.new_session(
                    session_name=self.session_name)

            for win in self.config['windows']:
                print win, "***", self.config['windows']
                window = self.session.find_where({"window_name": win['name']})
                if window:
                    info('window %s already exists' % win['name'])
                else:
                    info('create window %s' % win['name'])
                    window = self.session.new_window(win['name'])
                exist_num_panes = len(window.list_panes())
                while exist_num_panes < len(win['panes']):
                    info('new pane needed in window %s' % win['name'])
                    window.split_window(vertical=1)
                    exist_num_panes = len(window.list_panes())
                window.cmd('select-layout', 'tiled')

    def find_window(self, window_name):
        for win in self.config['windows']:
            if win['name'] == window_name:
                window = self.session.find_where({"window_name": win['name']})
                #window.select_window()
                return win, window

    def send_ctrlc(self, pane):
        datestr = datetime.now().strftime('%c')
        pane.cmd("send-keys", "", "C-c")
        pane.cmd("send-keys", "", "C-c")
        pane.cmd("send-keys", "", "C-c")
        pane.send_keys('# tmux-controller sent Ctrl-C at %s' % datestr,
                       enter=True,
                       suppress_history=True)

    def launch_window(self, window_name, enter=True):
        info('launch %s' % window_name)
        winconf, window = self.find_window(window_name)
        pane_no = 0
        datestr = datetime.now().strftime('%c')
        for cmd in winconf['panes']:
            pane = window.select_pane(pane_no)
            self.send_ctrlc(pane)
            pane.send_keys('# tmux-controller starts new command %s' % datestr,
                           enter=True,
                           suppress_history=True)
            if 'init_cmd' in self.config:
                pane.send_keys(self.config['init_cmd'],
                               enter=enter,
                               suppress_history=False)
            pane.send_keys(cmd, enter=enter, suppress_history=False)
            pane_no += 1
        winconf['_running'] = True

    def launch_all_windows(self):
        for winconf in self.config['windows']:
            self.launch_window(winconf['name'])

    def stop_all_windows(self):
        for winconf in self.config['windows']:
            self.stop_window(winconf['name'])

    def get_children_pids_all_windows(self):
        pids = []
        for winconf in self.config['windows']:
            pids.extend(self.get_children_pids_window(winconf['name']))
        return pids

    def kill_all_windows(self):
        for winconf in self.config['windows']:
            self.kill_window(winconf['name'])
        self.server.kill_session(self.session_name)

    def stop_window(self, window_name):
        info('stop %s' % window_name)
        winconf, window = self.find_window(window_name)
        self._stop_window(winconf, window)

    def _stop_window(self, winconf, window):
        pane_no = 0
        for cmd in winconf['panes']:
            pane = window.select_pane(pane_no)
            self.send_ctrlc(pane)
            pane_no += 1
        pids = self._get_pids_window(window)
        sleep(.1)
        for p in pids:
            self._terminate(p)
        winconf['_running'] = False

    def kill_window(self, window_name):
        info('terminate %s' % window_name)
        winconf, window = self.find_window(window_name)
        #                       "-F '#{pane_active} #{pane_pid}")
        self._stop_window(winconf, window)
        pids = self._get_pids_window(window)
        for pid in pids:
            Process(pid).terminate()
        winconf['_running'] = False

    def list_windows(self):
        return [w['name'] for w in self.config['windows']]

    def get_pids_window(self, window_name):
        winconf, window = self.find_window(window_name)
        return self._get_pids_window(window)

    def _get_pids_window(self, window):
        r = window.cmd('list-panes', "-F #{pane_pid}")
        return [int(p) for p in r.stdout]

    def get_children_pids_window(self, window_name):
        winconf, window = self.find_window(window_name)
        return self._get_children_pids_window(window)

    def _get_children_pids_window(self, window):
        winpids = self._get_pids_window(window)
        pids = []
        for pid in winpids:
            pids.extend(self._get_children_pids(pid))
        return [p.pid for p in pids]

    def is_running(self, window_name):
        winconf, window = self.find_window(window_name)
        pids = self._get_children_pids_window(window)
        if len(pids) < 1:
            return False
        if 'check' in winconf:
            info('need to run check command')
            if call(winconf['check'], shell=True) == 0:
                return True
            else:
                return False
        else:
            return True

    def _server(self):
        import webnsock
        import web

        tmux_self = self

        class TMuxWebServer(webnsock.WebServer):
            def __init__(self):

                webnsock.WebServer.__init__(self)

                self._render = web.template.render(path.realpath(
                    path.join(path.dirname(__file__), 'www')),
                                                   base="base",
                                                   globals=globals())

                self_app = self

                class Index(self.page):
                    path = '/'

                    def GET(self):
                        return self_app._render.index(tmux_self.config)

                class Log(self.page):
                    path = '/log'

                    def GET(self):
                        lines = tmux_self.server.cmd('capture-pane', '-p',
                                                     '-C', '-S',
                                                     '-100000').stdout
                        return '\n'.join(lines)

        class TMuxWSProtocol(webnsock.JsonWSProtocol):
            def __init__(self):
                super(TMuxWSProtocol, self).__init__()

            def on_button(self, payload):
                info('button pressed: \n%s' % pformat(payload))
                window_name = payload['id']
                cmd = payload['cmd']
                if cmd == 'launch':
                    if window_name == '':
                        tmux_self.launch_all_windows()
                    else:
                        tmux_self.launch_window(window_name)
                elif cmd == 'stop':
                    if window_name == '':
                        tmux_self.stop_all_windows()
                    else:
                        tmux_self.stop_window(window_name)
                elif cmd == 'terminate':
                    tmux_self.kill_all_windows()
                    sleep(1)
                    tmux_self.init()

                sleep(1)
                self.sendJSON(self.on_status())

            def on_status(self, payload=None):
                info('status-requested: ')

                res = {'windows': {}, 'method': 'update_status'}
                for w in tmux_self.config['windows']:
                    res['windows'][w['name']] = tmux_self.is_running(w['name'])

                return res

                #return {'button_outcome': True}

        self.webserver = webnsock.WebserverThread(TMuxWebServer(), port=9999)
        self.backend = webnsock.WSBackend(TMuxWSProtocol)

        signal.signal(
            signal.SIGINT, lambda s, f: webnsock.signal_handler(
                self.webserver, self.backend, s, f))
        self.webserver.start()
        self.backend.talker(port=9998)