def _search(self, reverse_search=False): if self.search_string is None: raise NotifyError("No search pattern specified.") if not self.search_string: self.search_string = None return pos = self.focus_position original_position = pos wrapped = False while True: if reverse_search: obj, pos = self.body.get_prev(pos) else: obj, pos = self.body.get_next(pos) if obj is None: # wrap wrapped = True if reverse_search: obj, pos = self.body[-1], len(self.body) else: obj, pos = self.body[0], 0 if wrapped and ((pos > original_position and not reverse_search) or (pos < original_position and reverse_search)): raise NotifyError("Pattern not found: %r." % self.search_string) # FIXME: figure out nicer search api if hasattr(obj, "matches_search"): condition = obj.matches_search(self.search_string) else: condition = self.search_string in obj.original_widget.text if condition: self.set_focus(pos) self.reload_widget() break
def __init__(self, docker_object, ui, follow=False): """ :param docker_object: container to display logs :param ui: ui object so we refresh """ self.tag = "F" if follow else "L" self.display_name = docker_object.short_name if isinstance(docker_object, DockerContainer): try: pre_message = "Getting logs for container {}...".format(docker_object.short_name) ui.notify_message(pre_message) operation = docker_object.logs(follow=follow) ui.remove_notification_message(pre_message) ui.notify_widget(get_operation_notify_widget(operation, display_always=False)) if follow: self.widget = AsyncScrollableListBox(operation.response, ui) else: self.widget = ScrollableListBox(operation.response) except Exception as ex: # FIXME: let's catch 404 and print that container doesn't exist # instead of printing ugly HTTP error raise NotifyError("Error getting logs for container %s: %r" % (docker_object, ex)) else: raise NotifyError("Only containers have logs.") super().__init__()
def __init__(self, ui, docker_object, follow=False): """ :param docker_object: container to display logs :param ui: ui object so we can refresh """ self.display_name += "({})".format(docker_object.short_name) if isinstance(docker_object, DockerContainer): try: pre_message = "Getting logs for container {}...".format( docker_object.short_name) ui.notify_message(pre_message) if follow: # FIXME: this is a bit race-y -- we might lose some logs with this approach operation = docker_object.logs(follow=follow, lines=0) static_data = docker_object.logs(follow=False).response self.widget = AsyncScrollableListBox( operation.response, ui, static_data=static_data) else: operation = docker_object.logs(follow=follow) self.widget = ScrollableListBox(ui, operation.response) ui.remove_notification_message(pre_message) ui.notify_widget( get_operation_notify_widget(operation, display_always=False)) except Exception as ex: # FIXME: let's catch 404 and print that container doesn't exist # instead of printing ugly HTTP error raise NotifyError("Error getting logs for container %s: %r" % (docker_object, ex)) else: raise NotifyError("Only containers have logs.") super().__init__()
def find_next(self, s=None): logger.debug("searching next %r in %r", s, self.__class__.__name__) try: self.widget.find_next(s) except AttributeError as ex: logger.debug(repr(ex)) raise NotifyError("Can't search in this buffer.")
def __init__(self, docker_image, ui): """ :param docker_image: :param ui: ui object so we refresh """ if isinstance(docker_image, RootImage): raise NotifyError( "Image \"scratch\" doesn't provide any more information.") if docker_image.image_id == "<missing>": raise NotifyError( "This image (layer) is not available due to changes in docker-1.10 " "image representation.") self.docker_image = docker_image self.display_name = docker_image.short_name self.widget = ImageInfoWidget(ui, docker_image) super().__init__()
def __init__(self, docker_image, ui): """ :param docker_image: :param ui: ui object so we refresh """ if isinstance(docker_image, RootImage): raise NotifyError( "Image \"scratch\" doesn't provide any more information.") self.display_name = docker_image.short_name self.widget = ImageInfoWidget(ui, docker_image) super().__init__()
def realtime_updates(self): event = it = None while True: if not it or not event: it = repeater(self.client.events, kwargs={"decode": True}, retries=5) if not it: raise NotifyError("Unable to fetch realtime updates from docker engine.") event = repeater(next, args=(it, ), retries=2) # likely an engine restart if not event: continue logger.debug("RT event: %s", event) yield event
def _net(self): try: net = self.docker_container.net except NotAvailableAnymore: raise NotifyError("Container %s is not available anymore" % self.docker_container) ports = net.ports data = [] if ports: data.extend([[SelectableText("")], [ SelectableText("Host Port", maps=get_map("main_list_white")), SelectableText("Container Port", maps=get_map("main_list_white")) ]]) for container_port, host_port in ports.items(): if host_port and container_port: data.append([ SelectableText(host_port), SelectableText(container_port) ]) ips = net.ips logger.debug(ips) if ips: data.extend([[SelectableText("")], [ SelectableText("Network Name", maps=get_map("main_list_white")), SelectableText("IP Address", maps=get_map("main_list_white")) ]]) for net_name, net_data in ips.items(): a4 = net_data.get("ip_address4", "none") a6 = net_data.get("ip_address6", "") data.append([SelectableText(net_name), SelectableText(a4)]) if a6: data.append([SelectableText(net_name), SelectableText(a6)]) if data: self.view_widgets.extend( assemble_rows(data, dividechars=3, ignore_columns=[1]))
def realtime_updates(self): it = repeater(self.client.events, kwargs={"decode": True}, retries=5) while True: event = repeater(next, args=(it, ), retries=2) # likely an engine restart if not event: it = repeater(self.client.events, kwargs={"decode": True}, retries=5) if not it: raise NotifyError( "Unable to fetch realtime updates from docker engine.") continue logger.debug("RT event: %s", event) yield event continue # FIXME: this needs rewrite try: # 1.10+ is_container = event["Type"] == "container" except KeyError: # event["from'] means it's a container is_container = "from" in event if is_container: # inspect doesn't contain info about status and you can't query just one # container with containers() # let's do full-blown containers() query; it's not that expensive self.get_containers(cached=False) else: # similar as ^ # images() doesn't support query by ID # inspect doesn't contain info about repositories self.get_images(cached=False) content, _, _ = self.filter(containers=True, images=True, stopped=True, cached=True, sort_by_created=True) yield content
def query(self, query_string=""): """ query and display, also apply filters :param query_string: str :return: None """ def query_notify(operation): w = get_operation_notify_widget(operation, display_always=False) if w: self.ui.notify_widget(w) if query_string is not None: self.filter_query = query_string.strip() # FIXME: this could be part of filter command since it's command line backend_query = { "cached": False, "containers": True, "images": True, } def containers(): backend_query["containers"] = True backend_query["images"] = not backend_query["images"] backend_query["cached"] = True def images(): backend_query["containers"] = not backend_query["containers"] backend_query["images"] = True backend_query["cached"] = True def running(): backend_query["stopped"] = False backend_query["cached"] = True backend_query["images"] = False query_conf = [ { "query_keys": ["t", "type"], "query_values": ["c", "container", "containers"], "callback": containers }, { "query_keys": ["t", "type"], "query_values": ["i", "images", "images"], "callback": images }, { "query_keys": ["s", "state"], "query_values": ["r", "running"], "callback": running }, ] query_list = re.split(r"[\s,]", self.filter_query) unprocessed = [] for query_str in query_list: if not query_str: continue # process here x=y queries and pass rest to parent filter() try: query_key, query_value = query_str.split("=", 1) except ValueError: unprocessed.append(query_str) else: logger.debug("looking up query key %r and query value %r", query_key, query_value) for c in query_conf: if query_key in c["query_keys"] and query_value in c["query_values"]: c["callback"]() break else: raise NotifyError("Invalid query string: %r", query_str) widgets = [] logger.debug("doing query %s", backend_query) query, c_op, i_op = self.d.filter(**backend_query) for o in query: line = MainLineWidget(o) widgets.append(line) if unprocessed: new_query = " ".join(unprocessed) logger.debug("doing parent query for unprocessed string: %r", new_query) super().filter(new_query, widgets_to_filter=widgets) else: self.set_body(widgets) self.ro_content = widgets query_notify(i_op) query_notify(c_op)