Skip to content

Commit

Permalink
feat: Add parser container_inspect (#3562)
Browse files Browse the repository at this point in the history
* Add parser container_inspect

Signed-off-by: jiazhang <[email protected]>

* Update containers_inspect

Signed-off-by: jiazhang <[email protected]>

* Add parser

Signed-off-by: jiazhang <[email protected]>

* Update docs

Signed-off-by: jiazhang <[email protected]>

* Update format and description

Signed-off-by: jiazhang <[email protected]>

* Add back docker_container_inspect

Signed-off-by: jiazhang <[email protected]>

* Add deprecated warning

Signed-off-by: jiazhang <[email protected]>

* Fix string format

Signed-off-by: jiazhang <[email protected]>

* Update test data format

Signed-off-by: jiazhang <[email protected]>

* Update test data

Signed-off-by: jiazhang <[email protected]>

* Update test data

Signed-off-by: jiazhang <[email protected]>

* Update return value format

Signed-off-by: jiazhang <[email protected]>

* Update parser test data

Signed-off-by: jiazhang <[email protected]>

* Update datasource details

Signed-off-by: jiazhang <[email protected]>

* Update filter

Signed-off-by: jiazhang <[email protected]>

* Update docstring

Signed-off-by: jiazhang <[email protected]>

* Update doc

Signed-off-by: jiazhang <[email protected]>

* Update no_filters

Signed-off-by: jiazhang <[email protected]>

* Update default format

Signed-off-by: jiazhang <[email protected]>

* Update deprecated info

Signed-off-by: jiazhang <[email protected]>

* Update set format

Signed-off-by: jiazhang <[email protected]>

* Add a comment for condition checking if total_results is not null

Signed-off-by: jiazhang <[email protected]>

Signed-off-by: jiazhang <[email protected]>
  • Loading branch information
wushiqinlou authored Nov 3, 2022
1 parent 3cda84a commit 66e0d57
Show file tree
Hide file tree
Showing 10 changed files with 1,221 additions and 3 deletions.
8 changes: 8 additions & 0 deletions docs/custom_datasources_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ insights.specs.datasources.cloud_init
:show-inheritance:
:undoc-members:

insights.specs.datasources.container.containers_inspect
-------------------------------------------------------

.. automodule:: insights.specs.datasources.container.containers_inspect
:members: running_rhel_containers_id, containers_inspect_data_datasource
:show-inheritance:
:undoc-members:

insights.specs.datasources.container
------------------------------------

Expand Down
3 changes: 3 additions & 0 deletions docs/shared_parsers_catalog/containers_inspect.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.. automodule:: insights.parsers.containers_inspect
:members:
:show-inheritance:
47 changes: 47 additions & 0 deletions insights/parsers/containers_inspect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
ContainersInspect - commands ``docker|podman inspect``
======================================================
This parser reads the output of commands: "/usr/bin/docker|podman inspect <containers ID>"
which are used to show the metadata information of containers.
"""
from insights import parser, JSONParser
from insights.specs import Specs


@parser(Specs.containers_inspect)
class ContainersInspect(JSONParser):
"""
Class for parsing the output of the containers inspect commands
``/usr/bin/docker|podman inspect <containers ID>``
Typical Output of this command after datasource containers_inspect is::
[
{
"Id": "aeaea3ead527",
"Image": "538460c14d75dee1504e56ad8ddb7fe039093b1530ef8f90442a454b9aa3dc8b",
"engine": "podman",
"HostConfig|Privileged": false,
"Config|Cmd": ["sleep", "1000000"]
}
]
Attributes:
data (list): A list containing the parsed information
Examples:
>>> from insights.core.filters import add_filter
>>> from insights.specs import Specs
>>> add_filter(Specs.container_inspect_keys, ['HostConfig|Privileged'])
>>> str(inspect_containers.data[0]["Id"])
'aeaea3ead527'
>>> str(inspect_containers.data[0]["engine"])
'podman'
>>> inspect_containers.data[0]["HostConfig|Privileged"]
False
"""

def parse_content(self, content):
super(ContainersInspect, self).parse_content(content[0])
24 changes: 23 additions & 1 deletion insights/parsers/docker_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,29 @@
from insights.core.marshalling import unmarshal
from insights.parsers import SkipException
from insights.specs import Specs
from insights.util import deprecated


class DockerInspect(CommandParser, dict):
"""
.. warning::
This class is deprecated, please use
:py:class:`insights.parsers.containers_inspect.ContainersInspect` instead.
Parse the output of command "docker inspect --type=image" and "docker
inspect --type=container". The output of these two commands is formatted
as JSON, so "json.loads" is an option to parse the output in the future.
Raises:
SkipException: If content is not provided
"""
def __init__(self, *args, **kwargs):
deprecated(
DockerInspect,
"Please use the :class:`insights.parsers.containers_inspect.ContainersInspect` instead.",
"3.2.25"
)
super(DockerInspect, self).__init__(*args, **kwargs)

def parse_content(self, content):
if not content:
Expand Down Expand Up @@ -70,6 +82,10 @@ class DockerInspectImage(DockerInspect):
@parser(Specs.docker_container_inspect)
class DockerInspectContainer(DockerInspect):
"""
.. warning::
This parser is deprecated, please use
:py:class:`insights.parsers.containers_inspect.ContainersInspect` instead.
Parse docker container inspect output using the DockerInspect parser class.
Sample input::
Expand Down Expand Up @@ -98,4 +114,10 @@ class DockerInspectContainer(DockerInspect):
False
"""
pass
def __init__(self, *args, **kwargs):
deprecated(
DockerInspectContainer,
"Please use the :class:`insights.parsers.containers_inspect.ContainersInspect` instead.",
"3.2.25"
)
super(DockerInspectContainer, self).__init__(*args, **kwargs)
24 changes: 23 additions & 1 deletion insights/parsers/podman_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,29 @@
from insights.core.marshalling import unmarshal
from insights.parsers import SkipException
from insights.specs import Specs
from insights.util import deprecated


class PodmanInspect(CommandParser, dict):
"""
.. warning::
This class is deprecated, please use
:py:class:`insights.parsers.containers_inspect.ContainersInspect` instead.
Parse the output of command "podman inspect --type=image" and "podman
inspect --type=container". The output of these two commands is formatted
as JSON, so "json.loads" is an option to parse the output in the future.
Raises:
SkipException: If content is not provided
"""
def __init__(self, *args, **kwargs):
deprecated(
PodmanInspect,
"Please use the :class:`insights.parsers.containers_inspect.ContainersInspect` instead.",
"3.2.25"
)
super(PodmanInspect, self).__init__(*args, **kwargs)

def parse_content(self, content):
if not content:
Expand Down Expand Up @@ -66,6 +78,10 @@ class PodmanInspectImage(PodmanInspect):
@parser(Specs.podman_container_inspect)
class PodmanInspectContainer(PodmanInspect):
"""
.. warning::
This parser is deprecated, please use
:py:class:`insights.parsers.containers_inspect.ContainersInspect` instead.
Parse podman container inspect output using the PodmanInspect parser class.
Sample input::
Expand All @@ -91,4 +107,10 @@ class PodmanInspectContainer(PodmanInspect):
>>> container.get('State').get('Paused') is False
True
"""
pass
def __init__(self, *args, **kwargs):
deprecated(
PodmanInspectContainer,
"Please use the :class:`insights.parsers.containers_inspect.ContainersInspect` instead.",
"3.2.25"
)
super(PodmanInspectContainer, self).__init__(*args, **kwargs)
2 changes: 2 additions & 0 deletions insights/specs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,3 +792,5 @@ class Specs(SpecSet):
container_redhat_release = RegistryPoint(multi_output=True)
container_nginx_conf = RegistryPoint(multi_output=True)
container_installed_rpms = RegistryPoint(multi_output=True)
container_inspect_keys = RegistryPoint(filterable=True)
containers_inspect = RegistryPoint()
94 changes: 94 additions & 0 deletions insights/specs/datasources/container/containers_inspect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""
Custom datasources for containers inspect information
"""
import json
import os
from insights.core.context import HostContext
from insights.core.dr import SkipComponent
from insights.core.filters import get_filters
from insights.core.plugins import datasource, ContentException
from insights.core.spec_factory import DatasourceProvider, foreach_execute
from insights.specs import Specs
from insights.specs.datasources.container import running_rhel_containers


@datasource(running_rhel_containers, HostContext)
def running_rhel_containers_id(broker):
"""
Returns a list of container_id of the running containers.
"""
containers_info = []
for container in broker[running_rhel_containers]:
containers_info.append((container[1], container[2]))
return containers_info


class LocalSpecs(Specs):
""" Local specs used only by docker|podman_inspect datasources """

containers_inspect_data_raw = foreach_execute(running_rhel_containers_id, "/usr/bin/%s inspect %s")
""" Returns the output of command ``/usr/bin/docker|podman inspect <container ID>`` """


@datasource(LocalSpecs.containers_inspect_data_raw, HostContext)
def containers_inspect_data_datasource(broker):
"""
This datasource provides the filtered information collected
from ``/usr/bin/docker|podman inspect <container ID>``.
.. note::
The path of the target key is like raw_data[key1][key2][target_key],
then the filter pattern is like "key1|key2|target_key".
If the value type of raw_data[key1][key2] is list, although the target_key is in the list,
the filter pattern must be "key1|key2", this datasource returns the whole value of the list.
The value of "Id" and "Image" are checked from raw data directly, no need filter these items.
Typical content of ``/usr/bin/docker|podman inspect <container ID>`` file is::
[
{
"Id": "aeaea3ead52724bb525bb2b5c619d67836250756920f0cb9884431ba53b476d8",
"Created": "2022-10-21T23:47:24.506159696-04:00",
"Path": "sleep"
...
}
...
]
Returns:
list: item is JSON string containing filtered information.
Raises:
SkipComponent: When the filter/path does not exist or any exception occurs.
"""
try:
no_filters = ['Id', 'Image']
filters = sorted(set(get_filters(Specs.container_inspect_keys)) - set(no_filters))
if filters:
total_results = []
for item in broker[LocalSpecs.containers_inspect_data_raw]:
raw_data = json.loads(''.join(item.content))[0]
engine, _, container_id = item.cmd.split(None)
filter_result = dict(Id=container_id, engine=os.path.basename(engine))
if 'Image' in raw_data:
filter_result['Image'] = raw_data['Image'].split("sha256:")[-1]
for item in filters:
val = raw_data
for key in item.split("|"):
if key in val:
val = val[key]
else:
break
# If the filtered key does not exist, skip it
if val == raw_data:
continue
filter_result[item] = val
total_results.append(filter_result)
# Generally the False branch of this condition will never reach, since the required component
# LocalSpecs.containers_inspect_data_raw can guarantee total_results is not null. However, it's worth
# leaving this condition as an explicit assertion to avoid unexpected situation.
if total_results:
return DatasourceProvider(content=json.dumps(total_results), relative_path='insights_containers/containers_inspect')
except Exception as e:
raise ContentException("Unexpected content exception:{e}".format(e=str(e)))
raise SkipComponent
3 changes: 2 additions & 1 deletion insights/specs/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
semanage, ssl_certificate, sys_fs_cgroup_memory_tasks_number, system_user_dirs, user_group, yum_updates, luks_devices)
from insights.specs.datasources.sap import sap_hana_sid, sap_hana_sid_SID_nr
from insights.specs.datasources.pcp import pcp_enabled, pmlog_summary_args
from insights.specs.datasources.container import running_rhel_containers
from insights.specs.datasources.container import running_rhel_containers, containers_inspect
from insights.specs.datasources.container.nginx_conf import nginx_conf as container_nginx_conf_ds


Expand Down Expand Up @@ -675,3 +675,4 @@ class DefaultSpecs(Specs):
container_installed_rpms = container_execute(running_rhel_containers, "rpm -qa --qf '%s'" % _rpm_format, context=HostContext, signum=signal.SIGTERM)
container_nginx_conf = container_collect(container_nginx_conf_ds)
container_redhat_release = container_collect(running_rhel_containers, "/etc/redhat-release")
containers_inspect = containers_inspect.containers_inspect_data_datasource
Loading

0 comments on commit 66e0d57

Please sign in to comment.