aboutsummaryrefslogtreecommitdiff
path: root/ansible/library
diff options
context:
space:
mode:
authorIvan Halomi <ivan.halomi@tietoevery.com>2021-05-31 11:57:28 +0200
committerMartin Hiner <m.hiner@partner.samsung.com>2023-10-20 17:51:52 +0200
commit9a3f46334506d655f302ebe4abcd23df7540bd80 (patch)
tree1049d14b3e66c381d599489bad71fd92e5936ed8 /ansible/library
parent13ba75cccf71373f7cb3315edd2182c05d4ec2ec (diff)
downloadkolla-ansible-9a3f46334506d655f302ebe4abcd23df7540bd80.tar.gz
kolla-ansible-9a3f46334506d655f302ebe4abcd23df7540bd80.zip
Add support of podman deployment
This change adds basic deployment based on Podman container manager as an alternative to Docker. Signed-off-by: Ivan Halomi <i.halomi@partner.samsung.com> Signed-off-by: Martin Hiner <m.hiner@partner.samsung.com> Signed-off-by: Petr Tuma <p.tuma@partner.samsung.com> Change-Id: I2b52964906ba8b19b8b1098717b9423ab954fa3d Depends-On: Ie4b4c1cf8fe6e7ce41eaa703b423dedcb41e3afc
Diffstat (limited to 'ansible/library')
-rw-r--r--ansible/library/kolla_container_facts.py63
-rw-r--r--ansible/library/kolla_container_volume_facts.py31
-rw-r--r--ansible/library/kolla_docker.py29
-rw-r--r--ansible/library/kolla_toolbox.py104
4 files changed, 184 insertions, 43 deletions
diff --git a/ansible/library/kolla_container_facts.py b/ansible/library/kolla_container_facts.py
index d9626097c..3f75a4478 100644
--- a/ansible/library/kolla_container_facts.py
+++ b/ansible/library/kolla_container_facts.py
@@ -13,10 +13,9 @@
# limitations under the License.
-import docker
-
from ansible.module_utils.basic import AnsibleModule
+
DOCUMENTATION = '''
---
module: kolla_container_facts
@@ -41,6 +40,11 @@ options:
- Name or names of the containers
required: False
type: str or list
+ container_engine:
+ description:
+ - Name of container engine to use
+ required: True
+ type: str
author: Jeffrey Zhang
'''
@@ -49,6 +53,7 @@ EXAMPLES = '''
tasks:
- name: Gather docker facts
kolla_container_facts:
+ container_engine: docker
- name: Gather glance container facts
kolla_container_facts:
@@ -56,24 +61,18 @@ EXAMPLES = '''
name:
- glance_api
- glance_registry
+ container_engine: podman
'''
def get_docker_client():
+ import docker
return docker.APIClient
-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')
- )
-
- module = AnsibleModule(argument_spec=argument_spec)
-
- results = dict(changed=False, _containers=[])
+def use_docker(module, results):
client = get_docker_client()(version=module.params.get('api_version'))
+
containers = client.containers()
names = module.params.get('name')
if names and not isinstance(names, list):
@@ -86,6 +85,46 @@ def main():
continue
results['_containers'].append(container)
results[container_name] = container
+
+
+def use_podman(module, results):
+ import podman.errors as pe
+ from podman import PodmanClient
+
+ client = PodmanClient(base_url="http+unix:/run/podman/podman.sock")
+
+ try:
+ containers = client.containers.list(all=True, ignore_removed=True)
+ except pe.APIError as e:
+ module.fail_json(failed=True, msg=f"Internal error: {e.explanation}")
+ names = module.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
+ results['_containers'].append(container.attrs)
+ 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')
+ )
+
+ module = AnsibleModule(argument_spec=argument_spec)
+
+ results = dict(changed=False, _containers=[])
+ if module.params['container_engine'] == 'podman':
+ use_podman(module, results)
+ else:
+ use_docker(module, results)
+
module.exit_json(**results)
diff --git a/ansible/library/kolla_container_volume_facts.py b/ansible/library/kolla_container_volume_facts.py
index b1f471d22..a5aba0c9e 100644
--- a/ansible/library/kolla_container_volume_facts.py
+++ b/ansible/library/kolla_container_volume_facts.py
@@ -13,16 +13,14 @@
# limitations under the License.
-import docker
-
from ansible.module_utils.basic import AnsibleModule
DOCUMENTATION = '''
---
module: kolla_container_volume_facts
-short_description: Module for collecting Docker container volume facts
+short_description: Module for collecting container volume facts
description:
- - A module targeted at collecting Docker container volume facts. It is used
+ - A module targeted at collecting container volume facts. It is used
for detecting whether the container volume exists on a host.
options:
container_engine:
@@ -60,9 +58,25 @@ EXAMPLES = '''
def get_docker_client():
+ import docker
return docker.APIClient
+def get_docker_volumes(api_version):
+ client = get_docker_client()(version=api_version)
+ return client.volumes()['Volumes']
+
+
+def get_podman_volumes():
+ from podman import PodmanClient
+
+ client = PodmanClient(base_url="http+unix:/run/podman/podman.sock")
+ volumes = []
+ for volume in client.volumes.list():
+ volumes.append(volume.attrs)
+ return volumes
+
+
def main():
argument_spec = dict(
name=dict(required=False, type='list', default=[]),
@@ -73,12 +87,15 @@ def main():
module = AnsibleModule(argument_spec=argument_spec)
results = dict(changed=False, _volumes=[])
- client = get_docker_client()(version=module.params.get('api_version'))
- volumes = client.volumes()
+ if module.params.get('container_engine') == 'docker':
+ volumes = get_docker_volumes(module.params.get('api_version'))
+ else:
+ volumes = get_podman_volumes()
+
names = module.params.get('name')
if names and not isinstance(names, list):
names = [names]
- for volume in volumes['Volumes']:
+ for volume in volumes:
volume_name = volume['Name']
if names and volume_name not in names:
continue
diff --git a/ansible/library/kolla_docker.py b/ansible/library/kolla_docker.py
index 93788e35f..c19b7eb4f 100644
--- a/ansible/library/kolla_docker.py
+++ b/ansible/library/kolla_docker.py
@@ -16,22 +16,25 @@
# a hacky way to seed most usages of kolla_docker in kolla-ansible ansible
# playbooks - caution has to be exerted when setting "common_options"
-import traceback
+# FIXME(yoctozepto): restart_policy is *not* checked in the container
from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.kolla_docker_worker import DockerWorker
+import traceback
+
+from ansible.module_utils.kolla_container_worker import ContainerWorker
+
DOCUMENTATION = '''
---
module: kolla_docker
-short_description: Module for controlling Docker
+short_description: Module for controlling containers
description:
- - A module targeting at controlling Docker as used by Kolla.
+ - A module targeting at controlling container engine as used by Kolla.
options:
common_options:
description:
- A dict containing common params such as login info
- required: False
+ required: True
type: dict
default: dict()
action:
@@ -397,17 +400,23 @@ def generate_module():
def main():
module = generate_module()
- dw = None
+ cw: ContainerWorker = None
try:
- dw = DockerWorker(module)
+ if module.params.get('container_engine') == 'docker':
+ from ansible.module_utils.kolla_docker_worker import DockerWorker
+ cw = DockerWorker(module)
+ else:
+ from ansible.module_utils.kolla_podman_worker import PodmanWorker
+ cw = PodmanWorker(module)
+
# TODO(inc0): We keep it bool to have ansible deal with consistent
# types. If we ever add method that will have to return some
# meaningful data, we need to refactor all methods to return dicts.
- result = bool(getattr(dw, module.params.get('action'))())
- module.exit_json(changed=dw.changed, result=result, **dw.result)
+ result = bool(getattr(cw, module.params.get('action'))())
+ module.exit_json(changed=cw.changed, result=result, **cw.result)
except Exception:
module.fail_json(changed=True, msg=repr(traceback.format_exc()),
- **getattr(dw, 'result', {}))
+ **getattr(cw, 'result', {}))
if __name__ == '__main__':
diff --git a/ansible/library/kolla_toolbox.py b/ansible/library/kolla_toolbox.py
index 388d678ad..acfc8a15a 100644
--- a/ansible/library/kolla_toolbox.py
+++ b/ansible/library/kolla_toolbox.py
@@ -13,7 +13,6 @@
# limitations under the License.
from distutils.version import StrictVersion
-import docker
import json
import re
@@ -21,6 +20,7 @@ from ansible.module_utils.ansible_release import __version__ as ansible_version
from ansible.module_utils.basic import AnsibleModule
from ast import literal_eval
+from shlex import split
DOCUMENTATION = '''
---
@@ -120,10 +120,19 @@ def gen_commandline(params):
if StrictVersion(ansible_version) < StrictVersion('2.11.0'):
module_args = params.get('module_args')
else:
- module_args = literal_eval(params.get('module_args'))
+ try:
+ module_args = literal_eval(params.get('module_args'))
+ except SyntaxError:
+ if not isinstance(params.get('module_args'), str):
+ raise
+
+ # account for string arguments
+ module_args = split(params.get('module_args'))
if isinstance(module_args, dict):
module_args = ' '.join("{}='{}'".format(key, value)
for key, value in module_args.items())
+ if isinstance(module_args, list):
+ module_args = ' '.join(module_args)
command.extend(['-a', module_args])
if params.get('module_extra_vars'):
extra_vars = params.get('module_extra_vars')
@@ -134,6 +143,7 @@ def gen_commandline(params):
def get_docker_client():
+ import docker
return docker.APIClient
@@ -142,17 +152,7 @@ def docker_supports_environment_in_exec(client):
return docker_version >= StrictVersion('1.25')
-def main():
- specs = dict(
- container_engine=dict(required=True, type='str'),
- module_name=dict(required=True, type='str'),
- module_args=dict(type='str'),
- module_extra_vars=dict(type='json'),
- api_version=dict(required=False, type='str', default='auto'),
- timeout=dict(required=False, type='int', default=180),
- user=dict(required=False, type='str'),
- )
- module = AnsibleModule(argument_spec=specs, bypass_checks=True)
+def use_docker(module):
client = get_docker_client()(
version=module.params.get('api_version'),
timeout=module.params.get('timeout'))
@@ -240,7 +240,83 @@ def main():
# No way to know whether changed - assume yes.
ret['changed'] = True
- module.exit_json(**ret)
+ return ret
+
+
+def get_kolla_toolbox():
+ from podman import PodmanClient
+
+ with PodmanClient(base_url="http+unix:/run/podman/podman.sock") as client:
+ for cont in client.containers.list(all=True):
+ cont.reload()
+ if cont.name == 'kolla_toolbox' and cont.status == 'running':
+ return cont
+
+
+def use_podman(module):
+ from podman.errors.exceptions import APIError
+
+ try:
+ kolla_toolbox = get_kolla_toolbox()
+ if not kolla_toolbox:
+ module.fail_json(msg='kolla_toolbox container is not running.')
+
+ kwargs = {}
+ if 'user' in module.params:
+ kwargs['user'] = module.params['user']
+ environment = {"ANSIBLE_STDOUT_CALLBACK": "json",
+ "ANSIBLE_LOAD_CALLBACK_PLUGINS": "True"}
+ command_line = gen_commandline(module.params)
+
+ _, raw_output = kolla_toolbox.exec_run(
+ command_line,
+ environment=environment,
+ tty=True,
+ **kwargs
+ )
+ except APIError as e:
+ module.fail_json(msg=f'Encountered Podman API error: {e.explanation}')
+
+ try:
+ json_output = raw_output.decode('utf-8')
+ output = json.loads(json_output)
+ except Exception:
+ module.fail_json(
+ msg='Can not parse the inner module output: %s' % json_output)
+
+ try:
+ ret = output['plays'][0]['tasks'][0]['hosts']['localhost']
+ except (KeyError, IndexError):
+ module.fail_json(
+ msg='Ansible JSON output has unexpected format: %s' % output)
+
+ # Remove Ansible's internal variables from returned fields.
+ ret.pop('_ansible_no_log', None)
+
+ return ret
+
+
+def main():
+ specs = dict(
+ container_engine=dict(required=True, type='str'),
+ module_name=dict(required=True, type='str'),
+ module_args=dict(type='str'),
+ module_extra_vars=dict(type='json'),
+ api_version=dict(required=False, type='str', default='auto'),
+ timeout=dict(required=False, type='int', default=180),
+ user=dict(required=False, type='str'),
+ )
+ module = AnsibleModule(argument_spec=specs, bypass_checks=True)
+
+ container_engine = module.params.get('container_engine').lower()
+ if container_engine == 'docker':
+ result = use_docker(module)
+ elif container_engine == 'podman':
+ result = use_podman(module)
+ else:
+ module.fail_json(msg='Missing or invalid container engine.')
+
+ module.exit_json(**result)
if __name__ == "__main__":