Merge of container_facts modules
Merge container_facts and container_volume_facts into a single module for retrieving all information about containers and volumes. Change-Id: I5d321b8326edd7f3b7a11dbdc821e534f457f9d7 Signed-off-by: Ivan Halomi <ivan.halomi@tietoevry.com> Signed-off-by: Roman Krček <roman.krcek@tietoevry.com>
This commit is contained in:
parent
8f2781f25e
commit
32cdbd23d5
@ -1,4 +1,5 @@
|
||||
# Copyright 2016 99cloud
|
||||
# Copyright 2023 StackHPC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -45,7 +46,7 @@ options:
|
||||
- The action to perform
|
||||
required: True
|
||||
type: str
|
||||
author: Jeffrey Zhang
|
||||
author: Jeffrey Zhang, Michal Nasiadka
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@ -76,6 +77,18 @@ EXAMPLES = '''
|
||||
name:
|
||||
- glance_api
|
||||
action: get_containers_env
|
||||
|
||||
- name: Gather glance volume facts
|
||||
kolla_container_facts:
|
||||
container_engine: docker
|
||||
name:
|
||||
- glance_api
|
||||
action: get_volumes
|
||||
|
||||
- name: Gather all volume facts
|
||||
kolla_container_facts:
|
||||
container_engine: docker
|
||||
action: get_volumes
|
||||
'''
|
||||
|
||||
|
||||
@ -150,6 +163,20 @@ class ContainerFactsWorker():
|
||||
envs = self._remap_envs(cont['Config']['Env'])
|
||||
self.result['envs'][name] = envs
|
||||
|
||||
def get_volumes(self):
|
||||
"""Handles when module is called with action get_volumes."""
|
||||
names = self.params.get('name')
|
||||
self.result['volumes'] = dict()
|
||||
|
||||
if isinstance(names, str):
|
||||
names = [names]
|
||||
|
||||
volumes = self.client.volumes.list()
|
||||
for volume in volumes:
|
||||
if names and volume.name not in names:
|
||||
continue
|
||||
self.result['volumes'][volume.name] = volume.attrs
|
||||
|
||||
|
||||
class DockerFactsWorker(ContainerFactsWorker):
|
||||
def __init__(self, module):
|
||||
@ -188,7 +215,8 @@ def main():
|
||||
action=dict(required=True, type='str',
|
||||
choices=['get_containers',
|
||||
'get_containers_env',
|
||||
'get_containers_state']),
|
||||
'get_containers_state',
|
||||
'get_volumes']),
|
||||
)
|
||||
|
||||
required_if = [
|
||||
|
@ -1,108 +0,0 @@
|
||||
# Copyright 2023 StackHPC
|
||||
#
|
||||
# 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 ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: kolla_container_volume_facts
|
||||
short_description: Module for collecting container volume facts
|
||||
description:
|
||||
- A module targeted at collecting container volume facts. It is used
|
||||
for detecting whether the container volume exists on a host.
|
||||
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 container volumes
|
||||
required: False
|
||||
type: str or list
|
||||
author: Jeffrey Zhang / Michal Nasiadka
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- hosts: all
|
||||
tasks:
|
||||
- name: Gather docker facts
|
||||
kolla_container_volume_facts:
|
||||
|
||||
- name: Gather glance container facts
|
||||
kolla_container_volume_facts:
|
||||
container_engine: docker
|
||||
name:
|
||||
- glance_api
|
||||
- glance_registry
|
||||
'''
|
||||
|
||||
|
||||
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=[]),
|
||||
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, _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:
|
||||
volume_name = volume['Name']
|
||||
if names and volume_name not in names:
|
||||
continue
|
||||
results['_volumes'].append(volume)
|
||||
results[volume_name] = volume
|
||||
module.exit_json(**results)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -12,8 +12,9 @@
|
||||
|
||||
- name: Get container volume facts
|
||||
become: true
|
||||
kolla_container_volume_facts:
|
||||
kolla_container_facts:
|
||||
container_engine: "{{ kolla_container_engine }}"
|
||||
action: get_volumes
|
||||
name:
|
||||
- ovn_nb_db
|
||||
- ovn_sb_db
|
||||
@ -30,7 +31,7 @@
|
||||
assert:
|
||||
that:
|
||||
- neutron_plugin_agent == 'openvswitch'
|
||||
- container_volume_facts['ovn_nb_db'] is not defined
|
||||
- container_volume_facts['ovn_sb_db'] is not defined
|
||||
- container_volume_facts.volumes['ovn_nb_db'] is not defined
|
||||
- container_volume_facts.volumes['ovn_sb_db'] is not defined
|
||||
fail_msg: "ML2/OVS agent detected, neutron_plugin_agent is not set to 'openvswitch', Kolla-Ansible does not support this migration operation."
|
||||
when: container_facts.containers['neutron_openvswitch_agent'] is defined
|
||||
|
@ -1,8 +1,9 @@
|
||||
---
|
||||
- name: Checking for any existing OVN DB container volumes
|
||||
become: true
|
||||
kolla_container_volume_facts:
|
||||
kolla_container_facts:
|
||||
container_engine: "{{ kolla_container_engine }}"
|
||||
action: get_volumes
|
||||
name:
|
||||
- ovn_nb_db
|
||||
- ovn_sb_db
|
||||
@ -10,12 +11,12 @@
|
||||
|
||||
- name: Divide hosts by their OVN NB volume availability
|
||||
group_by:
|
||||
key: "ovn-nb-db_had_volume_{{ ovn_db_container_volume_facts['ovn_nb_db'] is defined }}"
|
||||
key: "ovn-nb-db_had_volume_{{ ovn_db_container_volume_facts.volumes['ovn_nb_db'] is defined }}"
|
||||
changed_when: false
|
||||
|
||||
- name: Divide hosts by their OVN SB volume availability
|
||||
group_by:
|
||||
key: "ovn-sb-db_had_volume_{{ ovn_db_container_volume_facts['ovn_sb_db'] is defined }}"
|
||||
key: "ovn-sb-db_had_volume_{{ ovn_db_container_volume_facts.volumes['ovn_sb_db'] is defined }}"
|
||||
changed_when: false
|
||||
|
||||
- name: Establish whether the OVN NB cluster has already existed
|
||||
|
@ -65,7 +65,23 @@ FAKE_DATA = {
|
||||
'Volumes': {'/var/lib/kolla/config_files/': {}}},
|
||||
'Mounts': {},
|
||||
'NetworkSettings': {}
|
||||
}
|
||||
},
|
||||
'volumes': [
|
||||
{'CreatedAt': '2024-10-10T12:05:46+02:00',
|
||||
'Driver': 'local',
|
||||
'Labels': None,
|
||||
'Mountpoint': '/var/lib/docker/volumes/my_volume/_data',
|
||||
'Name': 'my_volume',
|
||||
'Options': None,
|
||||
'Scope': 'local'},
|
||||
{'CreatedAt': '2023-05-01T14:55:36+02:00',
|
||||
'Driver': 'local',
|
||||
'Labels': None,
|
||||
'Mountpoint': '/var/lib/docker/volumes/another_volume/_data',
|
||||
'Name': 'another_volume',
|
||||
'Options': None,
|
||||
'Scope': 'local'}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@ -77,7 +93,7 @@ def get_DockerFactsWorker(mod_param, mock_client):
|
||||
return dfw
|
||||
|
||||
|
||||
def construct_container(cont_dict):
|
||||
def construct_container(cont_dict) -> mock.Mock:
|
||||
container = mock.Mock()
|
||||
container.name = cont_dict['Name']
|
||||
container.attrs = copy.deepcopy(cont_dict)
|
||||
@ -85,6 +101,14 @@ def construct_container(cont_dict):
|
||||
return container
|
||||
|
||||
|
||||
def contruct_volume(vol_dict: dict) -> mock.Mock:
|
||||
"""Creates volume object that mimics the output of a container client."""
|
||||
volume = mock.Mock()
|
||||
volume.name = vol_dict['Name']
|
||||
volume.attrs = copy.deepcopy(vol_dict)
|
||||
return volume
|
||||
|
||||
|
||||
def get_containers(override=None):
|
||||
if override:
|
||||
cont_dicts = override
|
||||
@ -100,6 +124,15 @@ def get_containers(override=None):
|
||||
return containers
|
||||
|
||||
|
||||
def get_volumes(override=None):
|
||||
if override:
|
||||
vol_dicts = override
|
||||
else:
|
||||
vol_dicts = copy.deepcopy(FAKE_DATA['volumes'])
|
||||
|
||||
return [contruct_volume(v) for v in vol_dicts]
|
||||
|
||||
|
||||
class TestContainerFacts(base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestContainerFacts, self).setUp()
|
||||
@ -202,3 +235,78 @@ class TestContainerFacts(base.BaseTestCase):
|
||||
'fake_container')
|
||||
self.dfw.module.fail_json.assert_called_once_with(
|
||||
msg="No such container: fake_container")
|
||||
|
||||
def test_get_volumes_single(self):
|
||||
"""Test fetching a single volume"""
|
||||
self.dfw = get_DockerFactsWorker(
|
||||
{'name': ['my_volume'], 'action': 'get_volumes'})
|
||||
full_vol_list = get_volumes(self.fake_data['volumes'])
|
||||
self.dfw.client.volumes.list.return_value = full_vol_list
|
||||
|
||||
self.dfw.get_volumes()
|
||||
|
||||
self.assertFalse(self.dfw.result['changed'])
|
||||
self.dfw.client.volumes.list.assert_called_once_with()
|
||||
self.assertIn('my_volume', self.dfw.result['volumes'])
|
||||
self.assertNotIn('another_volume', self.dfw.result['volumes'])
|
||||
self.assertEqual(len(self.dfw.result['volumes']), 1)
|
||||
self.assertDictEqual(
|
||||
self.dfw.result['volumes']['my_volume'],
|
||||
self.fake_data['volumes'][0])
|
||||
|
||||
def test_get_volumes_multiple(self):
|
||||
"""Test fetching multiple volumes"""
|
||||
self.dfw = get_DockerFactsWorker({
|
||||
'name': ['my_volume', 'another_volume'],
|
||||
'action': 'get_volumes'})
|
||||
full_vol_list = get_volumes(self.fake_data['volumes'])
|
||||
self.dfw.client.volumes.list.return_value = full_vol_list
|
||||
|
||||
self.dfw.get_volumes()
|
||||
|
||||
self.assertFalse(self.dfw.result['changed'])
|
||||
self.dfw.client.volumes.list.assert_called_once_with()
|
||||
self.assertIn('my_volume', self.dfw.result['volumes'])
|
||||
self.assertIn('another_volume', self.dfw.result['volumes'])
|
||||
self.assertEqual(len(self.dfw.result['volumes']), 2)
|
||||
self.assertDictEqual(
|
||||
self.dfw.result['volumes']['my_volume'],
|
||||
self.fake_data['volumes'][0])
|
||||
self.assertDictEqual(
|
||||
self.dfw.result['volumes']['another_volume'],
|
||||
self.fake_data['volumes'][1])
|
||||
|
||||
def test_get_volumes_all(self):
|
||||
"""Test fetching all volumes when no specific names are provided"""
|
||||
self.dfw = get_DockerFactsWorker({'name': [],
|
||||
'action': 'get_volumes'})
|
||||
full_vol_list = get_volumes(self.fake_data['volumes'])
|
||||
self.dfw.client.volumes.list.return_value = full_vol_list
|
||||
|
||||
self.dfw.get_volumes()
|
||||
|
||||
self.assertFalse(self.dfw.result['changed'])
|
||||
self.dfw.client.volumes.list.assert_called_once_with()
|
||||
self.assertIn('my_volume', self.dfw.result['volumes'])
|
||||
self.assertIn('another_volume', self.dfw.result['volumes'])
|
||||
self.assertDictEqual(
|
||||
self.dfw.result['volumes']['my_volume'],
|
||||
self.fake_data['volumes'][0])
|
||||
self.assertDictEqual(
|
||||
self.dfw.result['volumes']['another_volume'],
|
||||
self.fake_data['volumes'][1])
|
||||
|
||||
def test_get_volumes_negative(self):
|
||||
"""Test fetching a volume that doesn't exist"""
|
||||
self.dfw = get_DockerFactsWorker({'name': ['nonexistent_volume'],
|
||||
'action': 'get_volumes'})
|
||||
full_vol_list = get_volumes(self.fake_data['volumes'])
|
||||
self.dfw.client.volumes.list.return_value = full_vol_list
|
||||
|
||||
self.dfw.get_volumes()
|
||||
|
||||
self.assertFalse(self.dfw.result['changed'])
|
||||
self.dfw.client.volumes.list.assert_called_once_with()
|
||||
self.assertIn('volumes', self.dfw.result)
|
||||
self.assertEqual(len(self.dfw.result['volumes']), 0)
|
||||
self.assertNotIn('nonexistent_volume', self.dfw.result['volumes'])
|
||||
|
Loading…
x
Reference in New Issue
Block a user