aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ansible/library/kolla_container_facts.py32
-rw-r--r--ansible/library/kolla_container_volume_facts.py108
-rw-r--r--ansible/roles/neutron/tasks/neutron_plugin_agent_check.yml7
-rw-r--r--ansible/roles/ovn-db/tasks/lookup_cluster.yml7
-rw-r--r--tests/test_kolla_container_facts.py112
5 files changed, 148 insertions, 118 deletions
diff --git a/ansible/library/kolla_container_facts.py b/ansible/library/kolla_container_facts.py
index 041aa3904..18c194c9f 100644
--- a/ansible/library/kolla_container_facts.py
+++ b/ansible/library/kolla_container_facts.py
@@ -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 = [
diff --git a/ansible/library/kolla_container_volume_facts.py b/ansible/library/kolla_container_volume_facts.py
deleted file mode 100644
index a5aba0c9e..000000000
--- a/ansible/library/kolla_container_volume_facts.py
+++ /dev/null
@@ -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()
diff --git a/ansible/roles/neutron/tasks/neutron_plugin_agent_check.yml b/ansible/roles/neutron/tasks/neutron_plugin_agent_check.yml
index 76b8e440d..0f89a0789 100644
--- a/ansible/roles/neutron/tasks/neutron_plugin_agent_check.yml
+++ b/ansible/roles/neutron/tasks/neutron_plugin_agent_check.yml
@@ -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
diff --git a/ansible/roles/ovn-db/tasks/lookup_cluster.yml b/ansible/roles/ovn-db/tasks/lookup_cluster.yml
index d97d358c7..86b4aa13a 100644
--- a/ansible/roles/ovn-db/tasks/lookup_cluster.yml
+++ b/ansible/roles/ovn-db/tasks/lookup_cluster.yml
@@ -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
diff --git a/tests/test_kolla_container_facts.py b/tests/test_kolla_container_facts.py
index 81e6a5009..f1fc59f3e 100644
--- a/tests/test_kolla_container_facts.py
+++ b/tests/test_kolla_container_facts.py
@@ -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'])