Exemplo n.º 1
0
 def __init__(self):
     self.monitored = ContainerMonitor(
         docker.Client('unix://var/run/docker.sock', '1.18'))
     self.monitored.get_containers()
     self.container_data = []
     self.containers = {}
     self.edit = AlwaysFocusedEdit("filter: ", multiline=False)
     self.listing = self.init_listing()
     self.filter = ""
     self.commands = ""
     self.marked_containers = {}
     self.in_inspect = False
     self.in_diff = False
     self.in_top = False
     self.size = ()
     Pane.__init__(self, urwid.Frame(
         self.listing,
         self.edit,
     ))
     self.original_widget.focus_position = 'body'
     urwid.connect_signal(self.monitored, 'container-list',
                          self.set_containers)
     self.counter = 1
Exemplo n.º 2
0
 def __init__(self):
     self.monitored = ContainerMonitor(docker.Client('unix://var/run/docker.sock', '1.18'))
     self.monitored.get_containers()
     self.container_data = []
     self.containers = {}
     self.edit = AlwaysFocusedEdit("filter: ", multiline=False)
     self.listing = self.init_listing()
     self.filter = ""
     self.commands = ""
     self.marked_containers = {}
     self.in_inspect = False
     self.in_diff = False
     self.in_top = False
     self.size = ()
     Pane.__init__(self, urwid.Frame(
         self.listing,
         self.edit,
     ))
     self.original_widget.focus_position = 'body'
     urwid.connect_signal(self.monitored, 'container-list', self.set_containers)
     self.counter = 1
Exemplo n.º 3
0
class ContainerPane(Pane):
    def __init__(self):
        self.monitored = ContainerMonitor(
            docker.Client('unix://var/run/docker.sock', '1.18'))
        self.monitored.get_containers()
        self.container_data = []
        self.containers = {}
        self.edit = AlwaysFocusedEdit("filter: ", multiline=False)
        self.listing = self.init_listing()
        self.filter = ""
        self.commands = ""
        self.marked_containers = {}
        self.in_inspect = False
        self.in_diff = False
        self.in_top = False
        self.size = ()
        Pane.__init__(self, urwid.Frame(
            self.listing,
            self.edit,
        ))
        self.original_widget.focus_position = 'body'
        urwid.connect_signal(self.monitored, 'container-list',
                             self.set_containers)
        self.counter = 1

    def init_listing(self):
        schema = (
            {
                'name': 'Id'
            },
            {
                'name': 'Image'
            },
            {
                'name': 'Command'
            },
            {
                'name': 'Status'
            },
            {
                'name': 'Names'
            },
        )
        return Table(schema, header=True)

    def make_container_row(self, container):
        if "seconds" in container['status']:
            container['status'] = "Up 0 minutes"
        row = self.listing.create_row({
            'Id': container['id'][:12],
            'Image': container['image'],
            'Command': container['command'],
            'Status': container['status'],
            'Names': container['names'],
        })
        row.image = container['image']
        row.container = container['id']
        row.name = container['names']
        row.status = container['status']
        self.containers[row.container] = row
        return row

    def set_containers(self, containers, force=False):
        # save the current position
        _, current_focus = self.listing.get_focus()

        if containers == self.container_data and not force:
            return

        self.listing.clear()
        self.old_containers = self.containers
        self.containers = {}

        running = [c for c in containers if 'Exited' not in c['status']]
        stopped = [c for c in containers if 'Exited' in c['status']]

        filter = self.filter.lower()

        def remove_highlight(row):
            highlighter.remove(row)

        for container in running:
            in_names = any(filter in name.lower()
                           for name in container['names'])
            in_id = filter in container['id'].lower()
            in_status = filter in container['status'].lower()
            in_image = filter in container['image'].lower()
            row = self.make_container_row(container)
            if any((in_names, in_id, in_status, in_image)):
                self.listing.walker.append(row)
                if self.old_containers and row.container not in self.old_containers:
                    highlighter.apply(row, 'created', 'created')
                    reactor.callLater(1, highlighter.remove, row)

        for container in stopped:
            in_names = any(filter in name.lower()
                           for name in container['names'])
            in_id = filter in container['id'].lower()
            in_status = filter in container['status'].lower()
            in_image = filter in container['image'].lower()
            row = self.make_container_row(container)
            if any((in_names, in_id, in_status, in_image)):
                self.listing.walker.append(row)
                if self.old_containers and row.container not in self.old_containers:
                    highlighter.apply(row, 'created', 'created')
                    reactor.callLater(1, highlighter.remove, row)

        self.container_data = containers
        self.listing.set_focus(current_focus)
        self.listing.fix_focus()
        app.draw_screen()

    def thread(self):
        return True

    def keypress(self, size, event):
        self.size = size
        self.since_time = time.time()
        if event == 'close-dialog':
            if self.in_inspect:
                self.in_inspect = False
            if self.in_diff:
                self.in_diff = False
            if self.in_top:
                self.in_top = False
        if event == 'scroll-close':
            event = 'close-dialog'
        if self.dialog:
            return super(ContainerPane, self).keypress(size, event)

        if self.listing.keypress(size, event):
            if self.handle_event(event):
                if not self.dialog and self.edit.keypress((size[0], ), event):
                    return super(ContainerPane, self).keypress(size, event)
                else:
                    self.filter = self.edit.edit_text
                    self.set_containers(self.container_data, force=True)
                    self.on_unmark()

        if event not in [
                'next-container', 'prev-container', 'set-mark',
                'unmark-containers'
        ]:
            thread = threading.Thread(name='thread', target=self.thread)
            listener = threading.Thread(name='listener', target=self.listener)
            listener.setDaemon(True)
            listener.start()
            thread.start()

    def handle_event(self, event):
        if event == 'next-container':
            self.on_next()
            if self.in_inspect or self.in_diff or self.in_top:
                self.keypress(self.size, 'scroll-close')
                if self.in_inspect:
                    self.on_inspect()
                if self.in_diff:
                    self.on_diff()
                if self.in_top:
                    self.on_top()
        elif event == 'prev-container':
            self.on_prev()
            if self.in_inspect or self.in_diff or self.in_top:
                self.keypress(self.size, 'scroll-close')
                if self.in_inspect:
                    self.on_inspect()
                if self.in_diff:
                    self.on_diff()
                if self.in_top:
                    self.on_top()
        elif event == 'toggle-show-all':
            self.on_all()
            self.monitored.get_containers()
        elif event == 'delete-container':
            self.dict_on_delete()
        elif event == 'commit-container':
            self.on_commit()
        elif event == 'inspect-details':
            self.in_inspect = True
            self.on_inspect()
        elif event == 'set-mark':
            self.on_mark()
        elif event == 'run-container(s)':
            self.on_run()
        elif event == 'unmark-containers':
            self.on_unmark()
        elif event == 'rename-container':
            self.on_rename()
            self.monitored.get_containers()
        elif event == 'inspect-changes':
            self.in_diff = True
            self.on_diff()
        elif event == 'restart-container':
            self.on_restart()
        elif event == 'kill-container':
            self.on_kill()
        elif event == 'pause-container':
            self.on_pause()
        elif event == 'unpause-container':
            self.on_unpause()
        elif event == 'start-container':
            self.on_start()
        elif event == 'stop-container':
            self.on_stop()
        elif event == 'top-container':
            self.in_top = True
            self.on_top()
        else:
            return super(ContainerPane, self).handle_event(event)

    def make_screen_command(self):
        row = 0
        none_marked = True
        for k, v in self.marked_containers.items():
            if v == "marked" and 'Exited' not in k.status:
                self.commands += "screen %d docker exec -it %s bash\n" % (
                    row, k.container)
                self.commands += "title %s\n" % k.image
                row += 1
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            if 'Exited' in widget.status:
                return
            self.commands += "screen 0 docker exec -it %s bash\n" % widget.container
            self.commands += "title %s\n" % widget.image
        self.commands += "caption always\n"
        temp = tempfile.NamedTemporaryFile()
        with open(temp.name, "wt") as fout:
            fout.write(self.commands)
        if self.commands == "":
            return
        subprocess.call(["screen", "-c" "%s" % temp.name])
        temp.close()
        app.client.close()
        raise urwid.ExitMainLoop

    def make_tmux_command(self):
        self.commands += "#!/bin/bash\n"
        self.commands += "tmux new-session -d -s run-containers\n"
        row = 1
        none_marked = True
        for k, v in self.marked_containers.items():
            if v == "marked" and 'Exited' not in k.status:
                self.commands += "tmux new-window -t run-containers:%d -n '%s' 'docker exec -it %s bash'\n" % (
                    row, k.image, k.container)
                row += 1
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            if 'Exited' in widget.status:
                return
            self.commands += "tmux new-window -t run-containers:1 -n '%s' 'docker exec -it %s bash'\n" % (
                widget.image, widget.container)
        self.commands += "tmux select-window -t run-containers:1\n"
        self.commands += "tmux -2 attach-session -t run-containers\n"
        temp = tempfile.NamedTemporaryFile()
        with open(temp.name, "wt") as fout:
            fout.write(self.commands)
        if self.commands == "":
            return
        subprocess.call(["rbash", "%s" % temp.name])
        temp.close()
        app.client.close()
        raise urwid.ExitMainLoop

    def make_command(self, which_mux):
        if (which_mux == "screen" or which_mux == "tmux or screen?: screen"
                or which_mux == "tmux or screen?:screen"):
            self.make_screen_command()
        elif (which_mux == "tmux" or which_mux == "tmux or screen?: tmux"
              or which_mux == "tmux or screen?:tmux"):
            self.make_tmux_command()
        else:
            self.on_run()

    def on_run(self):
        which_mux = "tmux or screen?: "
        prompt = Prompt(lambda which_mux: self.make_command(which_mux),
                        title="Run Container:",
                        initial=which_mux)
        self.show_dialog(prompt)

    def on_next(self):
        self.listing.next()

    def on_prev(self):
        self.listing.prev()

    def on_mark(self):
        marked_widget, marked_id = self.listing.get_focus()
        if (marked_widget in self.marked_containers
                and self.marked_containers[marked_widget] == "marked"):
            del self.marked_containers[marked_widget]
            self.listing.unmark()
        else:
            self.marked_containers[marked_widget] = "marked"
            self.listing.mark()

    def on_unmark(self):
        for key, value in self.marked_containers.items():
            if value == "marked":
                key.set_attr_map({None: None})
                del self.marked_containers[key]

    def on_all(self):
        self.on_unmark()
        self.monitored.all = not self.monitored.all

    def dict_on_delete(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                widget = key
                self.on_delete(widget)
                del self.marked_containers[key]
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.on_delete(widget)

    @catch_docker_errors
    def on_delete(self, widget):
        highlighter.apply(widget, 'deleted', 'deleted')
        reactor.callLater(2.5, highlighter.remove, widget)
        return threads.deferToThread(app.client.remove_container,
                                     widget.container)

    @catch_docker_errors
    def perform_start(self, widget):
        return threads.deferToThread(app.client.start, widget)

    def on_start(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                self.perform_start(key.container)
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_start(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_stop(self, widget):
        return threads.deferToThread(app.client.stop, widget)

    def on_stop(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                self.perform_stop(key.container)
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_stop(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_pause(self, widget):
        return threads.deferToThread(app.client.pause, widget)

    def on_pause(self):
        none_marked = True
        if len(self.marked_containers) > 0:
            for key, value in self.marked_containers.items():
                if value == "marked":
                    self.perform_pause(key.container)
                    none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_pause(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_unpause(self, widget):
        return threads.deferToThread(app.client.unpause, widget)

    def on_unpause(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                self.perform_unpause(key.container)
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_unpause(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_kill(self, widget):
        return threads.deferToThread(app.client.kill, widget)

    def on_kill(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                self.perform_kill(key.container)
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_kill(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_commit(self, container, repo_name):
        name, tag = split_repo_name(repo_name)
        repo_name = name + ":" + (tag or 'latest')
        self.close_dialog()
        return threads.deferToThread(app.client.commit, container, name, tag
                                     or 'latest')

    def on_commit(self):
        widget, idx = self.listing.get_focus()
        name, tag = split_repo_name(widget.image)
        prompt = Prompt(
            lambda name: self.perform_commit(widget.container, name),
            title="Tag Container",
            initial=name)
        self.show_dialog(prompt)

    @catch_docker_errors
    def perform_restart(self, widget):
        return threads.deferToThread(app.client.restart, widget)

    def on_restart(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                self.perform_restart(key.container)
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_restart(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_rename(self, container, name):
        self.close_dialog()
        return threads.deferToThread(app.client.rename, container, name)

    def on_rename(self):
        widget, idx = self.listing.get_focus()
        name = clean_name(widget.name[0])
        prompt = Prompt(
            lambda name: self.perform_rename(widget.container, name),
            title="Rename Container",
            initial=name)
        self.show_dialog(prompt)
        self.monitored.get_containers()

    @catch_docker_errors
    def on_inspect(self):
        widget, idx = self.listing.get_focus()
        d = threads.deferToThread(app.client.inspect_container,
                                  widget.container)
        d.addCallback(lambda data: self.show_dialog(ContainerInspector(data)))
        return d

    def _show_diff(self, diff_json, container_id):
        for d in diff_json:
            if d['Kind'] == 0:
                d['Kind'] = 'Change'
            elif d['Kind'] == 1:
                d['Kind'] = 'Add'
            elif d['Kind'] == 2:
                d['Kind'] = 'Delete'
        diffs = [(d.get('Kind', ''), d.get('Path', '')) for d in diff_json]
        dialog = TableDialog("Changes in %s" % container_id[:12], diffs,
                             [{
                                 'value': "kind",
                                 'weight': 1,
                                 'align': 'center'
                             }, {
                                 'value': "path",
                                 'weight': 4,
                                 'align': 'center'
                             }])
        dialog.width = ('relative', 90)
        self.show_dialog(dialog, )

    @catch_docker_errors
    def on_diff(self):
        widget, idx = self.listing.get_focus()
        d = threads.deferToThread(app.client.diff, widget.container)
        d.addCallback(self._show_diff, widget.container)
        d.addCallback(lambda r: app.draw_screen())
        return d

    def _show_top(self, top_json, container_id):
        processes = top_json.get('Processes', '')
        titles = top_json.get('Titles', '')
        dialog = TableDialog("Running Processes in %s" % container_id[:12],
                             processes, [
                                 {
                                     'value': titles[0],
                                     'weight': 3,
                                     'align': 'center'
                                 },
                                 {
                                     'value': titles[1],
                                     'weight': 3,
                                     'align': 'center'
                                 },
                                 {
                                     'value': titles[2],
                                     'weight': 3,
                                     'align': 'center'
                                 },
                                 {
                                     'value': titles[3],
                                     'weight': 1,
                                     'align': 'center'
                                 },
                                 {
                                     'value': titles[4],
                                     'weight': 3,
                                     'align': 'center'
                                 },
                                 {
                                     'value': titles[5],
                                     'weight': 3,
                                     'align': 'center'
                                 },
                                 {
                                     'value': titles[6],
                                     'weight': 3,
                                     'align': 'center'
                                 },
                                 {
                                     'value': titles[7],
                                     'weight': 10,
                                     'align': 'center'
                                 },
                             ])
        dialog.width = ('relative', 90)
        self.show_dialog(dialog, )

    @catch_docker_errors
    def on_top(self):
        widget, idx = self.listing.get_focus()
        d = threads.deferToThread(app.client.top, widget.container)
        d.addCallback(self._show_top, widget.container)
        d.addCallback(lambda r: app.draw_screen())
        return d

    def listener(self):
        s = socket.socket(socket.AF_UNIX)
        s.connect('/var/run/docker.sock')
        with closing(s):
            s.sendall(b'GET /events?since=%d HTTP/1.1\n\n' % self.since_time)
            header = s.recv(4096)
            chunk = s.recv(4096)
            self.monitored.get_containers()
Exemplo n.º 4
0
class ContainerPane(Pane):
    def __init__(self):
        self.monitored = ContainerMonitor(docker.Client('unix://var/run/docker.sock', '1.18'))
        self.monitored.get_containers()
        self.container_data = []
        self.containers = {}
        self.edit = AlwaysFocusedEdit("filter: ", multiline=False)
        self.listing = self.init_listing()
        self.filter = ""
        self.commands = ""
        self.marked_containers = {}
        self.in_inspect = False
        self.in_diff = False
        self.in_top = False
        self.size = ()
        Pane.__init__(self, urwid.Frame(
            self.listing,
            self.edit,
        ))
        self.original_widget.focus_position = 'body'
        urwid.connect_signal(self.monitored, 'container-list', self.set_containers)
        self.counter = 1
    
    def init_listing(self):
        schema = (
            {'name': 'Id'},
            {'name': 'Image'},
            {'name': 'Command'},
            {'name': 'Status'},
            {'name': 'Names'},
        )
        return Table(schema, header=True)

    def make_container_row(self, container):
        if "seconds" in container['status']: 
            container['status'] = "Up 0 minutes"
        row = self.listing.create_row({
            'Id': container['id'][:12],
            'Image': container['image'],
            'Command': container['command'],
            'Status': container['status'],
            'Names': container['names'],
        })
        row.image = container['image']
        row.container = container['id']
        row.name = container['names']
        row.status = container['status']
        self.containers[row.container] = row
        return row

    def set_containers(self, containers, force=False):
        # save the current position
        _, current_focus = self.listing.get_focus()

        if containers == self.container_data and not force:
            return

        self.listing.clear()
        self.old_containers = self.containers
        self.containers = {}

        running = [c for c in containers if 'Exited' not in c['status']]
        stopped = [c for c in containers if 'Exited' in c['status']]

        filter = self.filter.lower()

        def remove_highlight(row):
            highlighter.remove(row)

        for container in running:
            in_names = any(filter in name.lower() for name in container['names'])
            in_id = filter in container['id'].lower()
            in_status = filter in container['status'].lower()
            in_image = filter in container['image'].lower()
            row = self.make_container_row(container)
            if any((in_names, in_id, in_status, in_image)):
                self.listing.walker.append(row)
                if self.old_containers and row.container not in self.old_containers:
                    highlighter.apply(row, 'created', 'created')
                    reactor.callLater(1, highlighter.remove, row)

        for container in stopped:
            in_names = any(filter in name.lower() for name in container['names'])
            in_id = filter in container['id'].lower()
            in_status = filter in container['status'].lower()
            in_image = filter in container['image'].lower()
            row = self.make_container_row(container)
            if any((in_names, in_id, in_status, in_image)):
                self.listing.walker.append(row)
                if self.old_containers and row.container not in self.old_containers:
                    highlighter.apply(row, 'created', 'created')
                    reactor.callLater(1, highlighter.remove, row)

        self.container_data = containers
        self.listing.set_focus(current_focus)
        self.listing.fix_focus()
        app.draw_screen()

    def thread(self):
        return True

    def keypress(self, size, event):
        self.size = size
        self.since_time = time.time()
        if event == 'close-dialog':
            if self.in_inspect:
                self.in_inspect = False
            if self.in_diff:
                self.in_diff = False
            if self.in_top:
                self.in_top = False
        if event == 'scroll-close':
            event = 'close-dialog'
        if self.dialog:
            return super(ContainerPane, self).keypress(size, event)

        if self.listing.keypress(size, event):
            if self.handle_event(event):
                if not self.dialog and self.edit.keypress((size[0], ), event):
                    return super(ContainerPane, self).keypress(size, event)
                else:
                    self.filter = self.edit.edit_text
                    self.set_containers(self.container_data, force=True)
                    self.on_unmark()

        if event not in ['next-container', 'prev-container', 'set-mark', 'unmark-containers']:
            thread = threading.Thread(name='thread', target=self.thread)
            listener = threading.Thread(name='listener', target=self.listener)
            listener.setDaemon(True)
            listener.start()
            thread.start()

    def handle_event(self, event):
        if event == 'next-container':
            self.on_next()
            if self.in_inspect or self.in_diff or self.in_top:
                self.keypress(self.size, 'scroll-close')
                if self.in_inspect:
                    self.on_inspect()
                if self.in_diff:
                    self.on_diff()
                if self.in_top:
                    self.on_top()
        elif event== 'prev-container':
            self.on_prev()
            if self.in_inspect or self.in_diff or self.in_top:
                self.keypress(self.size, 'scroll-close')
                if self.in_inspect:
                    self.on_inspect()
                if self.in_diff:
                    self.on_diff()
                if self.in_top:
                    self.on_top()
        elif event == 'toggle-show-all':
            self.on_all()
            self.monitored.get_containers()
        elif event == 'delete-container':
            self.dict_on_delete()
        elif event == 'commit-container':
            self.on_commit()
        elif event == 'inspect-details':
            self.in_inspect = True
            self.on_inspect()
        elif event == 'set-mark':
            self.on_mark()
        elif event == 'run-container(s)':
            self.on_run()
        elif event == 'unmark-containers':
            self.on_unmark()
        elif event == 'rename-container':
            self.on_rename()
            self.monitored.get_containers()
        elif event == 'inspect-changes':
            self.in_diff = True
            self.on_diff()
        elif event == 'restart-container':
            self.on_restart()
        elif event == 'kill-container':
            self.on_kill()
        elif event == 'pause-container':
            self.on_pause()
        elif event == 'unpause-container':
            self.on_unpause()
        elif event == 'start-container':
            self.on_start()
        elif event == 'stop-container':
            self.on_stop()
        elif event == 'top-container':
            self.in_top = True
            self.on_top()
        else:
            return super(ContainerPane, self).handle_event(event)

    def make_screen_command(self):
        row = 0
        none_marked = True
        for k, v in self.marked_containers.items():
            if v == "marked" and 'Exited' not in k.status:
                self.commands += "screen %d docker exec -it %s bash\n" % (row, k.container)
                self.commands += "title %s\n" % k.image
                row += 1
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            if 'Exited' in widget.status:
                return
            self.commands += "screen 0 docker exec -it %s bash\n" % widget.container
            self.commands += "title %s\n" % widget.image
        self.commands += "caption always\n"
        temp = tempfile.NamedTemporaryFile()
        with open(temp.name, "wt") as fout:
            fout.write(self.commands)
        if self.commands == "":
            return
        subprocess.call(["screen", "-c" "%s" % temp.name])
        temp.close()
        app.client.close()
        raise urwid.ExitMainLoop

    def make_tmux_command(self):
        self.commands += "#!/bin/bash\n"
        self.commands += "tmux new-session -d -s run-containers\n"
        row = 1
        none_marked = True
        for k, v in self.marked_containers.items():
            if v == "marked" and 'Exited' not in k.status:
                self.commands += "tmux new-window -t run-containers:%d -n '%s' 'docker exec -it %s bash'\n" % (row, k.image, k.container)
                row += 1
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            if 'Exited' in widget.status:
                return
            self.commands += "tmux new-window -t run-containers:1 -n '%s' 'docker exec -it %s bash'\n" % (widget.image, widget.container)
        self.commands += "tmux select-window -t run-containers:1\n"
        self.commands += "tmux -2 attach-session -t run-containers\n"
        temp = tempfile.NamedTemporaryFile()
        with open(temp.name, "wt") as fout:
            fout.write(self.commands)
        if self.commands == "":
            return
        subprocess.call(["rbash", "%s" % temp.name])
        temp.close()
        app.client.close()
        raise urwid.ExitMainLoop

    def make_command(self, which_mux):
        if (which_mux == "screen" or which_mux == "tmux or screen?: screen"
                or which_mux == "tmux or screen?:screen"):
            self.make_screen_command()
        elif (which_mux == "tmux" or which_mux == "tmux or screen?: tmux"
                or which_mux == "tmux or screen?:tmux"):
            self.make_tmux_command()
        else:
            self.on_run()

    def on_run(self):
        which_mux = "tmux or screen?: "
        prompt = Prompt(lambda which_mux: self.make_command(which_mux), title="Run Container:", initial=which_mux)
        self.show_dialog(prompt)

    def on_next(self):
        self.listing.next()

    def on_prev(self):
        self.listing.prev()

    def on_mark(self):
        marked_widget, marked_id = self.listing.get_focus()
        if (marked_widget in self.marked_containers and 
                self.marked_containers[marked_widget] == "marked"):
            del self.marked_containers[marked_widget]
            self.listing.unmark()
        else:
            self.marked_containers[marked_widget] = "marked"
            self.listing.mark()

    def on_unmark(self):
        for key, value in self.marked_containers.items():
            if value == "marked":
                key.set_attr_map({None:None})
                del self.marked_containers[key]

    def on_all(self):
        self.on_unmark()
        self.monitored.all = not self.monitored.all
    
    def dict_on_delete(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                widget = key
                self.on_delete(widget)
                del self.marked_containers[key]
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.on_delete(widget)

    @catch_docker_errors
    def on_delete(self, widget):
        highlighter.apply(widget, 'deleted', 'deleted')
        reactor.callLater(2.5, highlighter.remove, widget)
        return threads.deferToThread(app.client.remove_container, widget.container)

    @catch_docker_errors
    def perform_start(self, widget):
        return threads.deferToThread(app.client.start, widget)

    def on_start(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                self.perform_start(key.container)
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_start(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_stop(self, widget):
        return threads.deferToThread(app.client.stop, widget)

    def on_stop(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                self.perform_stop(key.container)
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_stop(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_pause(self, widget):
        return threads.deferToThread(app.client.pause, widget)
        
    def on_pause(self):
        none_marked = True
        if len(self.marked_containers) > 0:
            for key, value in self.marked_containers.items():
                if value == "marked":
                    self.perform_pause(key.container)                
                    none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_pause(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_unpause(self, widget):
        return threads.deferToThread(app.client.unpause, widget)

    def on_unpause(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                self.perform_unpause(key.container)
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_unpause(widget.container)
        else:
            self.on_unmark()
    
    @catch_docker_errors
    def perform_kill(self, widget):
        return threads.deferToThread(app.client.kill, widget)

    def on_kill(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                self.perform_kill(key.container)
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_kill(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_commit(self, container, repo_name):
        name, tag = split_repo_name(repo_name)
        repo_name = name + ":" + (tag or 'latest')
        self.close_dialog()
        return threads.deferToThread(app.client.commit, container, name, tag or 'latest')

    def on_commit(self):
        widget, idx = self.listing.get_focus()
        name, tag = split_repo_name(widget.image)
        prompt = Prompt(lambda name: self.perform_commit(widget.container, name), title="Tag Container", initial=name)
        self.show_dialog(prompt)

    @catch_docker_errors
    def perform_restart(self, widget):
        return threads.deferToThread(app.client.restart, widget)

    def on_restart(self):
        none_marked = True
        for key, value in self.marked_containers.items():
            if value == "marked":
                self.perform_restart(key.container)
                none_marked = False
        if none_marked:
            widget, idx = self.listing.get_focus()
            self.perform_restart(widget.container)
        else:
            self.on_unmark()

    @catch_docker_errors
    def perform_rename(self, container, name):
        self.close_dialog()
        return threads.deferToThread(app.client.rename, container, name)
        
    def on_rename(self):
        widget, idx = self.listing.get_focus()
        name = clean_name(widget.name[0])
        prompt = Prompt(lambda name: self.perform_rename(widget.container, name), title="Rename Container", initial=name)
        self.show_dialog(prompt)
        self.monitored.get_containers()

    @catch_docker_errors
    def on_inspect(self):
        widget, idx = self.listing.get_focus()
        d = threads.deferToThread(app.client.inspect_container, widget.container)
        d.addCallback(lambda data: self.show_dialog(ContainerInspector(data)))
        return d

    def _show_diff(self, diff_json, container_id):
        for d in diff_json:
            if d['Kind'] == 0:
                d['Kind'] = 'Change'
            elif d['Kind'] == 1:
                d['Kind'] = 'Add'
            elif d['Kind'] == 2:
                d['Kind'] = 'Delete'
        diffs = [(d.get('Kind',''), d.get('Path','')) for d in diff_json]
        dialog = TableDialog(
            "Changes in %s" % container_id[:12],
            diffs,
            [
                {'value':"kind", 'weight':1, 'align':'center'},
                {'value':"path", 'weight':4, 'align':'center'}
            ]
        )
        dialog.width = ('relative', 90)
        self.show_dialog(dialog, )

    @catch_docker_errors
    def on_diff(self):
        widget, idx = self.listing.get_focus()
        d = threads.deferToThread(app.client.diff, widget.container)
        d.addCallback(self._show_diff, widget.container)
        d.addCallback(lambda r: app.draw_screen())
        return d

    def _show_top(self, top_json, container_id):
        processes = top_json.get('Processes','')
        titles = top_json.get('Titles','')
        dialog = TableDialog(
            "Running Processes in %s" % container_id[:12],
            processes,
            [
                {'value':titles[0], 'weight':3, 'align':'center'},
                {'value':titles[1], 'weight':3, 'align':'center'},
                {'value':titles[2], 'weight':3, 'align':'center'},
                {'value':titles[3], 'weight':1, 'align':'center'},
                {'value':titles[4], 'weight':3, 'align':'center'},
                {'value':titles[5], 'weight':3, 'align':'center'},
                {'value':titles[6], 'weight':3, 'align':'center'},
                {'value':titles[7], 'weight':10, 'align':'center'},
            ]
        )
        dialog.width = ('relative', 90)
        self.show_dialog(dialog, )

    @catch_docker_errors
    def on_top(self):
        widget, idx = self.listing.get_focus()
        d = threads.deferToThread(app.client.top, widget.container)
        d.addCallback(self._show_top, widget.container)
        d.addCallback(lambda r: app.draw_screen())
        return d

    def listener(self):
        s = socket.socket(socket.AF_UNIX)
        s.connect('/var/run/docker.sock')
        with closing(s):
            s.sendall(b'GET /events?since=%d HTTP/1.1\n\n' % self.since_time)
            header = s.recv(4096)
            chunk = s.recv(4096)
            self.monitored.get_containers()