Beispiel #1
0
class Containers(Atomic):

    FILTER_KEYWORDS= {"container": "id", "image": "image_name", "command": "command",
                      "created": "created", "state": "state", "runtime": "runtime", "backend" : "backend.backend"}

    def __init__(self):
        super(Containers, self).__init__()
        self.beu = BackendUtils()

    def fstrim(self):
        with AtomicDocker() as client:
            for container in client.containers():
                containerId = container["Id"]
                ret = self._inspect_container(name=containerId)
                pid = ret["State"]["Pid"]
                mp = "/proc/%d/root" % (pid)
                util.write_out("Trimming container id {0}".format(containerId[0:12]))
                util.check_call(["/usr/sbin/fstrim", "-v", mp], stdout=DEVNULL)
        return

    def filter_container_objects(self, con_objs):
        def _walk(_filter_objs, _filter, _value):
            _filtered = []
            for con_obj in _filter_objs:
                it = con_obj
                for i in _filter.split("."):
                    it = getattr(it, i, None)
                if _value.lower() in it.lower():
                    _filtered.append(con_obj)
            return _filtered

        if not self.args.filter:
            return con_objs
        for f in self.args.filter:
            cfilter, value = f.split('=', 1)
            cfilter = self.FILTER_KEYWORDS[cfilter]
            con_objs = _walk(con_objs, cfilter, value)
        return con_objs

    def ps_tty(self):
        if self.args.debug:
            util.write_out(str(self.args))
            self.beu.dump_backends()


        container_objects = self._ps()
        # If we were not asked for json output, return out with no output
        # when there are no applicable container objects
        if not self.args.json:
            if len(container_objects) == 0:
                return 0

            if not any([x.running for x in container_objects]) and not self.args.all:
                return 0

        # Set to 12 when truncate
        if self.args.truncate:
            max_container_id = 12
        # Otherwise set to the max, falling back to 0
        else:
            max_container_id = max([len(x.id) for x in container_objects] or [0])

        # Quiet supersedes json output
        if self.args.quiet:
            for con_obj in container_objects:
                util.write_out(con_obj.id[0:max_container_id])
            return 0

        if self.args.json:
            util.output_json(self._to_json(container_objects))
            return 0

        max_image_name = 20 if self.args.truncate else max([len(x.image_name) for x in container_objects])
        if self.args.truncate:
            max_command = 10
        else:
            _max_command = max([len(x.command) for x in container_objects])
            max_command = _max_command if _max_command > 9 else 10

        max_container_name = 10 if self.args.truncate else max([len(x.name) for x in container_objects])

        col_out = "{0:2} {1:%s} {2:%s} {3:%s} {4:%s} {5:16} {6:10} {7:10} {8:10}" % (max_container_id,
                                                                                     max_image_name,
                                                                                     max_container_name,
                                                                                     max_command)
        if self.args.heading:
            util.write_out(col_out.format(" ",
                                          "CONTAINER ID",
                                          "IMAGE",
                                          "NAME",
                                          "COMMAND",
                                          "CREATED",
                                          "STATE",
                                          "BACKEND",
                                          "RUNTIME"))
        for con_obj in container_objects:
            indicator = ""
            if con_obj.vulnerable:
                if util.is_python2:
                    indicator = indicator + self.skull + " "
                else:
                    indicator = indicator + str(self.skull, "utf-8") + " "
            util.write_out(col_out.format(indicator,
                                          con_obj.id[0:max_container_id],
                                          con_obj.image_name[0:max_image_name],
                                          con_obj.name[0:max_container_name],
                                          str(con_obj.command)[0:max_command],
                                          con_obj.created[0:16],
                                          con_obj.state[0:10],
                                          con_obj.backend.backend[0:10],
                                          con_obj.runtime[0:10]))

    def ps(self):
        container_objects = self._ps()
        return self._to_json(container_objects)

    def _ps(self):
        def _check_filters():
            if not self.args.filter:
                return True
            for f in self.args.filter:
                _filter, _ = f.split('=', 1)
                keywords = list(self.FILTER_KEYWORDS.keys())
                if _filter not in keywords:
                    raise ValueError("The filter {} is not valid.  "
                                     "Please choose from {}".format(_filter, keywords))
        _check_filters()
        containers = self.filter_container_objects(self.beu.get_containers())
        self._mark_vulnerable(containers)
        if self.args.all:
            return containers
        return [x for x in containers if x.running]

    @staticmethod
    def _to_json(con_objects):
        containers = []
        for con_obj in con_objects:
            _con = {'id': con_obj.id,
                    'image_id': con_obj.image,
                    'image_name': con_obj.image_name,
                    'name': con_obj.name,
                    'command': con_obj.command,
                    'created': con_obj.created,
                    'state': con_obj.state,
                    'backend': con_obj.backend.backend,
                    'runtime': con_obj.runtime,
                    'vulnerable': con_obj.vulnerable,
                    'running': con_obj.running
                    }
            containers.append(_con)
        return containers

    def delete(self):
        if self.args.debug:
            util.write_out(str(self.args))
            self.beu.dump_backends()

        if (len(self.args.containers) > 0 and self.args.all) or (len(self.args.containers) < 1 and not self.args.all):
            raise ValueError("You must select --all or provide a list of images to delete.")

        if self.args.all:
            if self.args.storage:
                be = self.beu.get_backend_from_string(self.args.storage)
                container_objects = be.get_containers()
            else:
                container_objects = self.beu.get_containers()
        else:
            container_objects = []
            for con in self.args.containers:
                _, con_obj = self.beu.get_backend_and_container_obj(con, str_preferred_backend=self.args.storage or storage, required=True if self.args.storage else False)
                container_objects.append(con_obj)

        if len(container_objects) == 0:
            raise ValueError("No containers to delete")
        four_col = "   {0:12} {1:20} {2:25} {3:10}"
        if not self.args.assumeyes:
            util.write_out("Do you wish to delete the following images?\n")
        else:
            util.write_out("The following containers will be deleted.\n")
        util.write_out(four_col.format("ID", "NAME", 'IMAGE_NAME', "STORAGE"))
        for con in container_objects:
            util.write_out(four_col.format(con.id[0:12], con.name[0:20], con.image_name[0:25], con.backend.backend))
        if not self.args.assumeyes:
            confirm = util.input("\nConfirm (y/N) ")
            confirm = confirm.strip().lower()
            if not confirm in ['y', 'yes']:
                util.write_err("User aborted delete operation for {}".format(self.args.containers or "all containers"))
                sys.exit(2)

        for del_con in container_objects:
            try:
                del_con.backend.delete_container(del_con.id, force=self.args.force)
            except APIError as e:
                util.write_err("Failed to delete container {}: {}".format(con.id, e))
        return 0

    def _mark_vulnerable(self, containers):
        assert isinstance(containers, list)
        vulnerable_uuids = self.get_vulnerable_ids()
        for con in containers:
            if con.id in vulnerable_uuids:
                con.vulnerable = True

    def update(self):
        if self.syscontainers.get_checkout(self.args.container):
            return self.syscontainers.update_container(self.args.container, self.args.setvalues, self.args.rebase)
        raise ValueError("System container '%s' is not installed" % self.args.container)

    def rollback(self):
        util.write_out("Attempting to roll back system container: %s" % self.args.container)
        self.syscontainers.rollback(self.args.container)
Beispiel #2
0
class Containers(Atomic):

    FILTER_KEYWORDS = {
        "container": "id",
        "image": "image_name",
        "command": "command",
        "created": "created",
        "state": "state",
        "runtime": "runtime",
        "backend": "backend.backend"
    }

    def __init__(self):
        super(Containers, self).__init__()
        self.beu = BackendUtils()

    def fstrim(self):
        with AtomicDocker() as client:
            for container in client.containers():
                containerId = container["Id"]
                ret = self._inspect_container(name=containerId)
                pid = ret["State"]["Pid"]
                mp = "/proc/%d/root" % (pid)
                util.write_out("Trimming container id {0}".format(
                    containerId[0:12]))
                util.check_call(["/usr/sbin/fstrim", "-v", mp], stdout=DEVNULL)
        return

    def filter_container_objects(self, con_objs):
        def _walk(_filter_objs, _filter, _value):
            _filtered = []
            for con_obj in _filter_objs:
                it = con_obj
                for i in _filter.split("."):
                    it = getattr(it, i, None)
                if _value.lower() in it.lower():
                    _filtered.append(con_obj)
            return _filtered

        if not self.args.filter:
            return con_objs
        for f in self.args.filter:
            cfilter, value = f.split('=', 1)
            cfilter = self.FILTER_KEYWORDS[cfilter]
            con_objs = _walk(con_objs, cfilter, value)
        return con_objs

    def ps_tty(self):
        if self.args.debug:
            util.write_out(str(self.args))
            self.beu.dump_backends()

        container_objects = self._ps()
        # If we were not asked for json output, return out with no output
        # when there are no applicable container objects
        if not self.args.json:
            if len(container_objects) == 0:
                return 0

            if not any([x.running
                        for x in container_objects]) and not self.args.all:
                return 0

        # Set to 12 when truncate
        if self.args.truncate:
            max_container_id = 12
        # Otherwise set to the max, falling back to 0
        else:
            max_container_id = max([len(x.id) for x in container_objects]
                                   or [0])

        # Quiet supersedes json output
        if self.args.quiet:
            for con_obj in container_objects:
                util.write_out(con_obj.id[0:max_container_id])
            return 0

        if self.args.json:
            util.output_json(self._to_json(container_objects))
            return 0

        max_image_name = 20 if self.args.truncate else max(
            [len(x.image_name) for x in container_objects])
        if self.args.truncate:
            max_command = 10
        else:
            _max_command = max([len(x.command) for x in container_objects])
            max_command = _max_command if _max_command > 9 else 10

        max_container_name = 10 if self.args.truncate else max(
            [len(x.name) for x in container_objects])

        col_out = "{0:2} {1:%s} {2:%s} {3:%s} {4:%s} {5:16} {6:10} {7:10} {8:10}" % (
            max_container_id, max_image_name, max_container_name, max_command)
        if self.args.heading:
            util.write_out(
                col_out.format(" ", "CONTAINER ID", "IMAGE", "NAME", "COMMAND",
                               "CREATED", "STATE", "BACKEND", "RUNTIME"))
        for con_obj in container_objects:
            indicator = ""
            if con_obj.vulnerable:
                if util.is_python2:
                    indicator = indicator + self.skull + " "
                else:
                    indicator = indicator + str(self.skull, "utf-8") + " "
            util.write_out(
                col_out.format(indicator, con_obj.id[0:max_container_id],
                               con_obj.image_name[0:max_image_name],
                               con_obj.name[0:max_container_name],
                               str(con_obj.command)[0:max_command],
                               con_obj.created[0:16], con_obj.state[0:10],
                               con_obj.backend.backend[0:10],
                               con_obj.runtime[0:10]))

    def ps(self):
        container_objects = self._ps()
        return self._to_json(container_objects)

    def _ps(self):
        def _check_filters():
            if not self.args.filter:
                return True
            for f in self.args.filter:
                _filter, _ = f.split('=', 1)
                keywords = list(self.FILTER_KEYWORDS.keys())
                if _filter not in keywords:
                    raise ValueError("The filter {} is not valid.  "
                                     "Please choose from {}".format(
                                         _filter, keywords))

        _check_filters()
        containers = self.filter_container_objects(self.beu.get_containers())
        self._mark_vulnerable(containers)
        if self.args.all:
            return containers
        return [x for x in containers if x.running]

    @staticmethod
    def _to_json(con_objects):
        containers = []
        for con_obj in con_objects:
            _con = {
                'id': con_obj.id,
                'image_id': con_obj.image,
                'image_name': con_obj.image_name,
                'name': con_obj.name,
                'command': con_obj.command,
                'created': con_obj.created,
                'state': con_obj.state,
                'backend': con_obj.backend.backend,
                'runtime': con_obj.runtime,
                'vulnerable': con_obj.vulnerable,
                'running': con_obj.running
            }
            containers.append(_con)
        return containers

    def delete(self):
        if self.args.debug:
            util.write_out(str(self.args))
            self.beu.dump_backends()

        if (len(self.args.containers) > 0
                and self.args.all) or (len(self.args.containers) < 1
                                       and not self.args.all):
            raise ValueError(
                "You must select --all or provide a list of images to delete.")

        if self.args.all:
            if self.args.storage:
                be = self.beu.get_backend_from_string(self.args.storage)
                container_objects = be.get_containers()
            else:
                container_objects = self.beu.get_containers()
        else:
            container_objects = []
            for con in self.args.containers:
                _, con_obj = self.beu.get_backend_and_container_obj(
                    con,
                    str_preferred_backend=self.args.storage or storage,
                    required=True if self.args.storage else False)
                container_objects.append(con_obj)

        if len(container_objects) == 0:
            raise ValueError("No containers to delete")
        four_col = "   {0:12} {1:20} {2:25} {3:10}"
        if not self.args.assumeyes:
            util.write_out("Do you wish to delete the following images?\n")
        else:
            util.write_out("The following containers will be deleted.\n")
        util.write_out(four_col.format("ID", "NAME", 'IMAGE_NAME', "STORAGE"))
        for con in container_objects:
            util.write_out(
                four_col.format(con.id[0:12], con.name[0:20],
                                con.image_name[0:25], con.backend.backend))
        if not self.args.assumeyes:
            confirm = util.input("\nConfirm (y/N) ")
            confirm = confirm.strip().lower()
            if not confirm in ['y', 'yes']:
                util.write_err("User aborted delete operation for {}".format(
                    self.args.containers or "all containers"))
                sys.exit(2)

        for del_con in container_objects:
            try:
                del_con.backend.delete_container(del_con.id,
                                                 force=self.args.force)
            except APIError as e:
                util.write_err("Failed to delete container {}: {}".format(
                    con.id, e))
        return 0

    def _mark_vulnerable(self, containers):
        assert isinstance(containers, list)
        vulnerable_uuids = self.get_vulnerable_ids()
        for con in containers:
            if con.id in vulnerable_uuids:
                con.vulnerable = True

    def update_all_containers(self):
        preupdate_containers = self.syscontainers.get_containers()
        could_not_update = {}
        for i in preupdate_containers:
            name = i['Names'][0]
            util.write_out("Checking container {}...".format(name))
            try:
                self.syscontainers.update_container(name, controlled=True)
            except:  # pylint: disable=bare-except
                could_not_update[name] = True

        postupdate_containers = self.syscontainers.get_containers()

        images_by_name = {
            i['RepoTags'][0]: i
            for i in self.syscontainers.get_system_images()
        }
        preupdate_containers_by_name = {
            i['Names'][0]: i
            for i in preupdate_containers
        }
        postupdate_containers_by_name = {
            i['Names'][0]: i
            for i in postupdate_containers
        }

        def get_image_id(c):
            return c['ImageId'] if 'ImageId' in c else c['ImageID']

        def colored(line, color):
            if sys.stdout.isatty():
                return "\x1b[1;%dm%s\x1b[0m" % (color, line)
            else:
                return line

        def get_status(container_name, pre_id, post_id, image_id):
            COLOR_RED = 31
            COLOR_GREEN = 32
            COLOR_YELLOW = 33

            if container_name in could_not_update:
                return "Failed", COLOR_RED
            if image_id == None:
                return "Unknown", COLOR_YELLOW
            if post_id == image_id and image_id != pre_id:
                return "Updated now", COLOR_GREEN
            if post_id == image_id and image_id == pre_id:
                return "Updated", COLOR_GREEN
            return "Not updated", COLOR_RED

        cols = "{0:15} {1:32} {2:32} {3:32} {4:15}"

        util.write_out("\nSUMMARY\n")
        util.write_out(
            cols.format("Container", "Image ID before update",
                        "Image ID after update", "Latest image ID", "Status"))
        for cnt in preupdate_containers_by_name.keys():
            pre_version = get_image_id(preupdate_containers_by_name[cnt])
            post_version = get_image_id(postupdate_containers_by_name[cnt])
            img_name = img_id = None
            try:
                img_name = preupdate_containers_by_name[cnt]['Image']
                img_id = get_image_id(images_by_name[img_name])
            except KeyError:
                pass
            status, color = get_status(cnt, pre_version, post_version, img_id)
            colored_status = colored(status[:15], color)
            util.write_out(
                cols.format(cnt[:15], pre_version[:32], post_version[:32],
                            (img_id or "<NOT FOUND>")[:32], colored_status))

    def update(self):
        if self.args.all:
            if self.args.container is not None:
                raise ValueError(
                    "Incompatible options specified.  --all doesn't support a container name"
                )
            if self.args.setvalues or self.args.rebase:
                raise ValueError(
                    "Incompatible options specified.  --all doesn't support --set or --rebase"
                )

            return self.update_all_containers()

        if self.args.container is None:
            raise ValueError(
                "Too few arguments.  Please specify the container")

        if self.syscontainers.get_checkout(self.args.container):
            return self.syscontainers.update_container(self.args.container,
                                                       self.args.setvalues,
                                                       self.args.rebase)
        raise ValueError("System container '%s' is not installed" %
                         self.args.container)

    def rollback(self):
        util.write_out("Attempting to roll back system container: %s" %
                       self.args.container)
        self.syscontainers.rollback(self.args.container)
Beispiel #3
0
class Containers(Atomic):

    FILTER_KEYWORDS = {
        "container": "id",
        "image": "image_name",
        "command": "command",
        "created": "created",
        "state": "state",
        "runtime": "runtime",
        "backend": "backend.backend"
    }

    def __init__(self):
        super(Containers, self).__init__()
        self.beu = BackendUtils()

    def fstrim(self):
        with AtomicDocker() as client:
            for container in client.containers():
                containerId = container["Id"]
                ret = self._inspect_container(name=containerId)
                pid = ret["State"]["Pid"]
                mp = "/proc/%d/root" % (pid)
                util.write_out("Trimming container id {0}".format(
                    containerId[0:12]))
                util.check_call(["/usr/sbin/fstrim", "-v", mp], stdout=DEVNULL)
        return

    def filter_container_objects(self, con_objs):
        def _walk(_filter_objs, _filter, _value):
            _filtered = []
            for con_obj in _filter_objs:
                it = con_obj
                for i in _filter.split("."):
                    it = getattr(it, i, None)
                if _value.lower() in it.lower():
                    _filtered.append(con_obj)
            return _filtered

        if not self.args.filters:
            return con_objs
        filtered_objs = copy.deepcopy(con_objs)
        for f in self.args.filters:
            cfilter, value = f.split('=', 1)
            cfilter = self.FILTER_KEYWORDS[cfilter]
            filtered_objs = _walk(filtered_objs, cfilter, value)
        return filtered_objs

    def ps_tty(self):
        if self.args.debug:
            util.write_out(str(self.args))
            self.beu.dump_backends()

        container_objects = self._ps()
        if not any([x.running
                    for x in container_objects]) and not self.args.all:
            return 0

        if self.args.quiet:
            for con_obj in container_objects:
                util.write_out(con_obj.id[:12])
            return 0
        if self.args.json:
            util.output_json(self._to_json(container_objects))
            return 0

        if len(container_objects) == 0:
            return 0

        max_container_id = 12 if self.args.truncate else max(
            [len(x.id) for x in container_objects])
        max_image_name = 20 if self.args.truncate else max(
            [len(x.image_name) for x in container_objects])
        max_command = 20 if self.args.truncate else max(
            [len(x.command) for x in container_objects])
        col_out = "{0:2} {1:%s} {2:%s} {3:%s} {4:16} {5:9} {6:10} {7:10}" % (
            max_container_id, max_image_name, max_command)
        if self.args.heading:
            util.write_out(
                col_out.format(" ", "CONTAINER ID", "IMAGE", "COMMAND",
                               "CREATED", "STATE", "BACKEND", "RUNTIME"))
        for con_obj in container_objects:
            indicator = ""
            if con_obj.vulnerable:
                if util.is_python2:
                    indicator = indicator + self.skull + " "
                else:
                    indicator = indicator + str(self.skull, "utf-8") + " "
            util.write_out(
                col_out.format(indicator, con_obj.id[0:max_container_id],
                               con_obj.image_name[0:max_image_name],
                               con_obj.command[0:max_command],
                               con_obj.created[0:16], con_obj.state[0:9],
                               con_obj.backend.backend[0:10],
                               con_obj.runtime[0:10]))

    def ps(self):
        container_objects = self._ps()
        return self._to_json(container_objects)

    def _ps(self):
        def _check_filters():
            if not self.args.filters:
                return True
            for f in self.args.filters:
                _filter, _ = f.split('=', 1)
                keywords = list(self.FILTER_KEYWORDS.keys())
                if _filter not in keywords:
                    raise ValueError("The filter {} is not valid.  "
                                     "Please choose from {}".format(
                                         _filter, keywords))

        _check_filters()
        containers = self.filter_container_objects(self.beu.get_containers())
        self._mark_vulnerable(containers)
        if self.args.all:
            return containers
        return [x for x in containers if x.running]

    @staticmethod
    def _to_json(con_objects):
        containers = []
        for con_obj in con_objects:
            _con = {
                'id': con_obj.id,
                'image_id': con_obj.image_id,
                'image_name': con_obj.image_name,
                'command': con_obj.command,
                'created': con_obj.created,
                'state': con_obj.state,
                'backend': con_obj.backend.backend,
                'runtime': con_obj.runtime,
                'vulnerable': con_obj.vulnerable,
                'running': con_obj.running
            }
            containers.append(_con)
        return containers

    def delete(self):
        if self.args.debug:
            util.write_out(str(self.args))
            self.beu.dump_backends()

        if (len(self.args.containers) > 0
                and self.args.all) or (len(self.args.containers) < 1
                                       and not self.args.all):
            raise ValueError(
                "You must select --all or provide a list of images to delete.")

        if self.args.all:
            if self.args.storage:
                be = self.beu.get_backend_from_string(self.args.storage)
                container_objects = be.get_containers()
            else:
                container_objects = self.beu.get_containers()
        else:
            container_objects = []
            for con in self.args.containers:
                _, con_obj = self.beu.get_backend_and_container_obj(
                    con,
                    str_preferred_backend=self.args.storage or storage,
                    required=True if self.args.storage else False)
                container_objects.append(con_obj)

        if len(container_objects) == 0:
            raise ValueError("No containers to delete")
        four_col = "   {0:12} {1:20} {2:25} {3:10}"
        if not self.args.assumeyes:
            util.write_out("Do you wish to delete the following images?\n")
        else:
            util.write_out("The following containers will be deleted.\n")
        util.write_out(four_col.format("ID", "NAME", 'IMAGE_NAME', "STORAGE"))
        for con in container_objects:
            util.write_out(
                four_col.format(con.id[0:12], con.name[0:20],
                                con.image_name[0:25], con.backend.backend))
        if not self.args.assumeyes:
            confirm = util.input("\nConfirm (y/N) ")
            confirm = confirm.strip().lower()
            if not confirm in ['y', 'yes']:
                util.write_err("User aborted delete operation for {}".format(
                    self.args.containers or "all containers"))
                sys.exit(2)

        for del_con in container_objects:
            try:
                del_con.backend.delete_container(del_con.id,
                                                 force=self.args.force)
            except APIError as e:
                util.write_err("Failed to delete container {}: {}".format(
                    con.id, e))
        return 0

    def _mark_vulnerable(self, containers):
        assert isinstance(containers, list)
        vulnerable_uuids = self.get_vulnerable_ids()
        for con in containers:
            if con.id in vulnerable_uuids:
                con.vulnerable = True

    def update(self):
        if self.syscontainers.get_checkout(self.args.container):
            return self.syscontainers.update_container(self.args.container,
                                                       self.args.setvalues,
                                                       self.args.rebase)
        raise ValueError("System container '%s' is not installed" %
                         self.args.container)

    def rollback(self):
        util.write_out("Attempting to roll back system container: %s" %
                       self.args.container)
        self.syscontainers.rollback(self.args.container)