kolla-ansible/ansible/library/kolla_container_facts.py
Ivan Halomi 4ce47e2250 Refactor of kolla_container_facts
Refactor that prepares kolla_container_facts
module for introducing more actions that will be moved
from kolla_container module and kolla_container_volume_facts.

This change is based on a discussion about adding a new action
to kolla_container module that retrieves all names of the running
containers. It was agreed that kolla-ansible should follow Ansible's
direction of splitting modules between action modules and facts
modules. Because of this, kolla_container_facts needs to be able
to handle different requests for data about containers or volumes.

Change-Id: Ieaec8f64922e4e5a2199db2d6983518b124cb4aa
Signed-off-by: Ivan Halomi <ivan.halomi@tietoevry.com>
2024-08-12 09:54:05 +02:00

169 lines
5.1 KiB
Python

# Copyright 2016 99cloud
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from abc import ABC
from abc import abstractmethod
from ansible.module_utils.basic import AnsibleModule
from traceback import format_exc
DOCUMENTATION = '''
---
module: kolla_container_facts
short_description: Module for collecting Docker container facts
description:
- A module targeting at collecting Docker container facts. It is used for
detecting whether the container is running on host in Kolla.
options:
container_engine:
description:
- Name of container engine to use
required: True
type: str
api_version:
description:
- The version of the api for docker-py to use when contacting docker
required: False
type: str
default: auto
name:
description:
- Name or names of the containers
required: False
type: str or list
action:
description:
- The action to perform
required: True
type: str
author: Jeffrey Zhang
'''
EXAMPLES = '''
- hosts: all
tasks:
- name: Gather docker facts
kolla_container_facts:
container_engine: docker
action: get_containers
- name: Gather glance container facts
kolla_container_facts:
container_engine: docker
name:
- glance_api
- glance_registry
container_engine: podman
action: get_containers
'''
class ContainerFactsWorker(ABC):
def __init__(self, module):
self.module = module
self.results = dict(changed=False, _containers=[])
self.params = module.params
@abstractmethod
def get_containers(self):
pass
class DockerFactsWorker(ContainerFactsWorker):
def __init__(self, module):
super().__init__(module)
try:
import docker
except ImportError:
self.module.fail_json(
msg="The docker library could not be imported")
self.client = docker.APIClient(version=module.params.get(
'api_version'))
def get_containers(self):
containers = self.client.containers()
names = self.params.get('name')
if names and not isinstance(names, list):
names = [names]
for container in containers:
for container_name in container['Names']:
# remove '/' prefix character
container_name = container_name[1:]
if names and container_name not in names:
continue
self.results['_containers'].append(container)
self.results[container_name] = container
class PodmanFactsWorker(ContainerFactsWorker):
def __init__(self, module):
try:
import podman.errors as podmanError
from podman import PodmanClient
except ImportError:
self.module.fail_json(
msg="The podman library could not be imported")
self.podmanError = podmanError
super().__init__(module)
self.client = PodmanClient(
base_url="http+unix:/run/podman/podman.sock")
def get_containers(self):
try:
containers = self.client.containers.list(
all=True, ignore_removed=True)
except self.podmanError.APIError as e:
self.module.fail_json(failed=True,
msg=f"Internal error: {e.explanation}")
names = self.params.get('name')
if names and not isinstance(names, list):
names = [names]
for container in containers:
container.reload()
container_name = container.attrs['Name']
if container_name not in names:
continue
self.results['_containers'].append(container.attrs)
self.results[container_name] = container.attrs
def main():
argument_spec = dict(
name=dict(required=False, type='list', default=[]),
api_version=dict(required=False, type='str', default='auto'),
container_engine=dict(required=True, type='str'),
action=dict(required=True, type='str',
choices=['get_containers']),
)
module = AnsibleModule(argument_spec=argument_spec)
cw: ContainerFactsWorker = None
try:
if module.params.get('container_engine') == 'docker':
cw = DockerFactsWorker(module)
else:
cw = PodmanFactsWorker(module)
result = bool(getattr(cw, module.params.get('action'))())
module.exit_json(result=result, **cw.results)
except Exception:
module.fail_json(changed=True, msg=repr(format_exc()),
**getattr(cw, 'result', {}))
if __name__ == "__main__":
main()