diff options
Diffstat (limited to 'tests')
| -rwxr-xr-x | tests/check-logs.sh | 3 | ||||
| -rwxr-xr-x | tests/j2lint.py | 88 | ||||
| -rw-r--r-- | tests/kolla_container_tests/test_docker_worker.py | 73 | ||||
| -rw-r--r-- | tests/kolla_container_tests/test_podman_worker.py | 364 | ||||
| -rw-r--r-- | tests/templates/globals-default.j2 | 50 | ||||
| -rw-r--r-- | tests/templates/inventory.j2 | 26 | ||||
| -rw-r--r-- | tests/templates/nova-compute-overrides.j2 | 4 | ||||
| -rw-r--r-- | tests/test_kolla_container_facts.py | 2 | ||||
| -rw-r--r-- | tests/test_kolla_toolbox.py | 47 | ||||
| -rw-r--r-- | tests/testinfra/test_horizon.py | 8 |
10 files changed, 450 insertions, 215 deletions
diff --git a/tests/check-logs.sh b/tests/check-logs.sh index c9953982c..650f2d7b2 100755 --- a/tests/check-logs.sh +++ b/tests/check-logs.sh @@ -42,6 +42,7 @@ function check_fluentd_missing_logs { /var/log/kolla/fluentd/fluentd.log) continue ;; + # TODO(mnasiadka): Remove me after G/2026.1 release /var/log/kolla/glance-tls-proxy/glance-tls-proxy.log) continue ;; @@ -69,7 +70,7 @@ function check_fluentd_missing_logs { /var/log/kolla/neutron/dnsmasq.log) continue ;; - # TODO(mnasiadka): Remove me in Gazpacho release + # TODO(mnasiadka): Remove me after G/2026.1 release /var/log/kolla/neutron-tls-proxy/neutron-tls-proxy.log) continue ;; diff --git a/tests/j2lint.py b/tests/j2lint.py deleted file mode 100755 index b3981af24..000000000 --- a/tests/j2lint.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2020 StackHPC Ltd. -# 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. - -""" -Original license: -@author Gerard van Helden <drm@melp.nl> -@license DBAD, see <http://www.dbad-license.org/> -@url https://github.com/drm/jinja2-lint -Simple j2 linter, useful for checking jinja2 template syntax - -Adapted for OpenStack Kolla/Kolla-Ansible purposes -""" - -from ansible.plugins.filter.core import get_encrypted_password -from ansible.plugins.filter.core import to_json -from functools import reduce -from jinja2 import BaseLoader -from jinja2 import Environment -from jinja2 import exceptions -from jinja2 import TemplateNotFound -from kolla_ansible import kolla_address -from kolla_ansible import put_address_in_context -import os.path -try: - from ansible_collections.ansible.utils.plugins.filter import ipwrap -except ImportError: - from ansible_collections.ansible.netcommon.plugins.filter import ipwrap - - -class AbsolutePathLoader(BaseLoader): - def get_source(self, environment, template): - if not os.path.exists(template): - raise TemplateNotFound(template) - mtime = os.path.getmtime(template) - with open(template) as file: - source = file.read() - return source, template, lambda: mtime == os.path.getmtime(template) - - -def check(template, out, err, env=Environment(loader=AbsolutePathLoader(), - autoescape=True)): - try: - env.filters['basename'] = os.path.basename - env.filters['bool'] = bool - env.filters['hash'] = hash - env.filters['to_json'] = to_json - # NOTE(wszumski): password_hash is mapped to the function: - # get_encrypted_password in ansible.filters.core. - env.filters['password_hash'] = get_encrypted_password - env.filters['kolla_address'] = kolla_address - env.filters['put_address_in_context'] = put_address_in_context - env.filters['ipwrap'] = ipwrap - env.get_template(template) - out.write("%s: Syntax OK\n" % template) - return 0 - except TemplateNotFound: - err.write("%s: File not found\n" % template) - return 2 - except exceptions.TemplateSyntaxError as ex: - err.write("%s: Syntax check failed: %s in %s at %d\n" - % (template, ex.message, ex.filename, ex.lineno)) - return 1 - - -def main(**kwargs): - import sys - try: - sys.exit(reduce(lambda r, fn: r + - check(fn, sys.stdout, sys.stderr, **kwargs), - sys.argv[1:], 0)) - except IndexError: - sys.stdout.write("Usage: j2lint.py filename [filename ...]\n") - - -if __name__ == "__main__": - main() diff --git a/tests/kolla_container_tests/test_docker_worker.py b/tests/kolla_container_tests/test_docker_worker.py index c79022462..26fe020f2 100644 --- a/tests/kolla_container_tests/test_docker_worker.py +++ b/tests/kolla_container_tests/test_docker_worker.py @@ -42,7 +42,7 @@ FAKE_DATA = { 'container_engine': 'docker', 'api_version': None, 'auth_username': None, - 'auth_password': None, + 'auth_password': None, # nosec B105 'auth_registry': None, 'restart_policy': None, 'auth_email': None, @@ -125,7 +125,7 @@ FAKE_DATA = { FAKE_DATA_COMMON_OPTS = { 'auth_username': 'kevko', - 'auth_password': 'SECRET', + 'auth_password': 'SECRET', # nosec B105 'auth_registry': 'Quay.io/kolla', 'restart_policy': 'unless-stopped', 'auth_email': 'kevko@kevko.org', @@ -144,7 +144,7 @@ def get_DockerWorker(mod_param, docker_api_version='1.40'): common_options_defaults = { 'auth_email': None, - 'auth_password': None, + 'auth_password': None, # nosec B105 'auth_registry': None, 'auth_username': None, 'environment': None, @@ -405,10 +405,13 @@ class TestContainer(base.BaseTestCase): self.assertEqual(self.dw.create_volume.call_count, 2) def test_start_container_without_pull(self): - self.fake_data['params'].update({'auth_username': 'fake_user', - 'auth_password': 'fake_psw', - 'auth_registry': 'myrepo/myapp', - 'auth_email': 'fake_mail@foogle.com'}) + params = { + 'auth_username': 'fake_user', + 'auth_password': 'fake_psw', # nosec B105 + 'auth_registry': 'myrepo/myapp', + 'auth_email': 'fake_mail@foogle.com' + } + self.fake_data['params'].update(params) self.dw = get_DockerWorker(self.fake_data['params']) self.dw.dc.images = mock.MagicMock( return_value=self.fake_data['images']) @@ -425,11 +428,14 @@ class TestContainer(base.BaseTestCase): self.dw.create_container.assert_called_once_with() def test_start_container_with_duplicate_name(self): - self.fake_data['params'].update({'name': 'my_container', - 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', - 'auth_registry': 'myrepo/myapp', - 'auth_email': 'fake_mail@foogle.com'}) + params = { + 'name': 'my_container', + 'auth_username': 'fake_user', + 'auth_password': 'fake_psw', # nosec B105 + 'auth_registry': 'myrepo/myapp', + 'auth_email': 'fake_mail@foogle.com' + } + self.fake_data['params'].update(params) self.dw = get_DockerWorker(self.fake_data['params']) self.dw.dc.images = mock.MagicMock( return_value=self.fake_data['images']) @@ -453,11 +459,14 @@ class TestContainer(base.BaseTestCase): self.dw.create_container.assert_called_once_with() def test_start_container(self): - self.fake_data['params'].update({'name': 'my_container', - 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', - 'auth_registry': 'myrepo/myapp', - 'auth_email': 'fake_mail@foogle.com'}) + params = { + 'name': 'my_container', + 'auth_username': 'fake_user', + 'auth_password': 'fake_psw', # nosec B105 + 'auth_registry': 'myrepo/myapp', + 'auth_email': 'fake_mail@foogle.com' + } + self.fake_data['params'].update(params) self.dw = get_DockerWorker(self.fake_data['params']) self.dw.dc.images = mock.MagicMock( return_value=self.fake_data['images']) @@ -497,12 +506,15 @@ class TestContainer(base.BaseTestCase): self.assertEqual(expected, self.dw.result) def test_start_container_no_systemd(self): - self.fake_data['params'].update({'name': 'my_container', - 'restart_policy': 'oneshot', - 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', - 'auth_registry': 'myrepo/myapp', - 'auth_email': 'fake_mail@foogle.com'}) + params = { + 'name': 'my_container', + 'restart_policy': 'oneshot', + 'auth_username': 'fake_user', + 'auth_password': 'fake_psw', # nosec B105 + 'auth_registry': 'myrepo/myapp', + 'auth_email': 'fake_mail@foogle.com' + } + self.fake_data['params'].update(params) self.dw = get_DockerWorker(self.fake_data['params']) self.dw.dc.images = mock.MagicMock( return_value=self.fake_data['images']) @@ -520,11 +532,14 @@ class TestContainer(base.BaseTestCase): self.dw.systemd.start.assert_not_called() def test_start_container_systemd_start_fail(self): - self.fake_data['params'].update({'name': 'my_container', - 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', - 'auth_registry': 'myrepo/myapp', - 'auth_email': 'fake_mail@foogle.com'}) + params = { + 'name': 'my_container', + 'auth_username': 'fake_user', + 'auth_password': 'fake_psw', # nosec B105 + 'auth_registry': 'myrepo/myapp', + 'auth_email': 'fake_mail@foogle.com' + } + self.fake_data['params'].update(params) self.dw = get_DockerWorker(self.fake_data['params']) self.dw.dc.images = mock.MagicMock( return_value=self.fake_data['images']) @@ -944,7 +959,7 @@ class TestImage(base.BaseTestCase): self.dw = get_DockerWorker( {'image': 'myregistrydomain.com:5000/ubuntu:16.04', 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', + 'auth_password': 'fake_psw', # nosec B105 'auth_registry': 'myrepo/myapp', 'auth_email': 'fake_mail@foogle.com' }) diff --git a/tests/kolla_container_tests/test_podman_worker.py b/tests/kolla_container_tests/test_podman_worker.py index e19f9517a..55ab5c165 100644 --- a/tests/kolla_container_tests/test_podman_worker.py +++ b/tests/kolla_container_tests/test_podman_worker.py @@ -299,10 +299,13 @@ class TestContainer(base.BaseTestCase): self.assertEqual(self.pw.create_volume.call_count, 2) def test_start_container_without_pull(self): - self.fake_data['params'].update({'auth_username': 'fake_user', - 'auth_password': 'fake_psw', - 'auth_registry': 'myrepo/myapp', - 'auth_email': 'fake_mail@foogle.com'}) + auth_params = { + 'auth_username': 'fake_user', + 'auth_password': 'fake_psw', # nosec B105 + 'auth_registry': 'myrepo/myapp', + 'auth_email': 'fake_mail@foogle.com' + } + self.fake_data['params'].update(auth_params) self.pw = get_PodmanWorker(self.fake_data['params'].copy()) self.pw.pc.images = mock.MagicMock( return_value=self.fake_data['images']) @@ -322,11 +325,14 @@ class TestContainer(base.BaseTestCase): self.pw.create_container.assert_called_once_with() def test_start_container_with_duplicate_name(self): - self.fake_data['params'].update({'name': 'my_container', - 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', - 'auth_registry': 'myrepo/myapp', - 'auth_email': 'fake_mail@foogle.com'}) + auth_params = { + 'name': 'my_container', + 'auth_username': 'fake_user', + 'auth_password': 'fake_psw', # nosec B105 + 'auth_registry': 'myrepo/myapp', + 'auth_email': 'fake_mail@foogle.com' + } + self.fake_data['params'].update(auth_params) self.pw = get_PodmanWorker(self.fake_data['params']) self.pw.pc.images = mock.MagicMock( return_value=self.fake_data['images']) @@ -348,11 +354,13 @@ class TestContainer(base.BaseTestCase): self.pw.create_container.assert_called_once_with() def test_start_container(self): - self.fake_data['params'].update({'name': 'my_container', - 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', - 'auth_registry': 'myrepo/myapp', - 'auth_email': 'fake_mail@foogle.com'}) + auth_params = { + 'auth_username': 'fake_user', + 'auth_password': 'fake_psw', # nosec B105 + 'auth_registry': 'myrepo/myapp', + 'auth_email': 'fake_mail@foogle.com' + } + self.fake_data['params'].update(auth_params) self.pw = get_PodmanWorker(self.fake_data['params']) self.pw.pc.images = mock.MagicMock( return_value=self.fake_data['images']) @@ -403,12 +411,15 @@ class TestContainer(base.BaseTestCase): self.assertEqual(expected, self.pw.result) def test_start_container_no_systemd(self): - self.fake_data['params'].update({'name': 'my_container', - 'restart_policy': 'oneshot', - 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', - 'auth_registry': 'myrepo/myapp', - 'auth_email': 'fake_mail@foogle.com'}) + auth_params = { + 'name': 'my_container', + 'restart_policy': 'oneshot', + 'auth_username': 'fake_user', + 'auth_password': 'fake_psw', # nosec B105 + 'auth_registry': 'myrepo/myapp', + 'auth_email': 'fake_mail@foogle.com' + } + self.fake_data['params'].update(auth_params) self.pw = get_PodmanWorker(self.fake_data['params']) self.pw.pc.images = mock.MagicMock( return_value=self.fake_data['images']) @@ -426,11 +437,14 @@ class TestContainer(base.BaseTestCase): self.pw.systemd.start.assert_not_called() def test_start_container_systemd_start_fail(self): - self.fake_data['params'].update({'name': 'my_container', - 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', - 'auth_registry': 'myrepo/myapp', - 'auth_email': 'fake_mail@foogle.com'}) + params = { + 'name': 'my_container', + 'auth_username': 'fake_user', + 'auth_password': 'fake_psw', # nosec B105 + 'auth_registry': 'myrepo/myapp', + 'auth_email': 'fake_mail@foogle.com' + } + self.fake_data['params'].update(params) self.pw = get_PodmanWorker(self.fake_data['params']) self.pw.pc.images = mock.MagicMock( return_value=self.fake_data['images']) @@ -817,7 +831,7 @@ class TestImage(base.BaseTestCase): self.pw = get_PodmanWorker( {'image': 'myregistrydomain.com:5000/ubuntu:16.04', 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', + 'auth_password': 'fake_psw', # nosec B105 'auth_registry': 'myrepo/myapp', 'auth_email': 'fake_mail@foogle.com' }) @@ -831,7 +845,8 @@ class TestImage(base.BaseTestCase): tag='16.04', tls_verify=False, stream=False, - auth_config={'username': 'fake_user', 'password': 'fake_psw'} + auth_config={'username': 'fake_user', + 'password': 'fake_psw'} # nosec B105 ) self.assertTrue(self.pw.changed) @@ -839,7 +854,7 @@ class TestImage(base.BaseTestCase): self.pw = get_PodmanWorker( {'image': 'myregistrydomain.com:5000/ubuntu:16.04', 'auth_username': 'fake_user', - 'auth_password': 'fake_psw', + 'auth_password': 'fake_psw', # nosec B105 'auth_registry': 'myrepo/myapp', 'auth_email': 'fake_mail@foogle.com' }) @@ -853,7 +868,8 @@ class TestImage(base.BaseTestCase): tag='16.04', tls_verify=False, stream=False, - auth_config={'username': 'fake_user', 'password': 'fake_psw'} + auth_config={'username': 'fake_user', + 'password': 'fake_psw'} # nosec B105 ) self.assertFalse(self.pw.changed) @@ -1094,16 +1110,72 @@ class TestAttrComp(base.BaseTestCase): super(TestAttrComp, self).setUp() self.fake_data = copy.deepcopy(FAKE_DATA) - def test_compare_cap_add_neg(self): - container_info = {'HostConfig': dict(CapAdd=['data'])} - self.pw = get_PodmanWorker({'cap_add': ['data']}) + def test_compare_cap_add_unprivileged_no_user_caps(self): + container_info = {'HostConfig': dict( + CapAdd=['CAP_AUDIT_WRITE'], + Privileged=False + )} + self.pw = get_PodmanWorker({'cap_add': []}) + self.assertFalse(self.pw.compare_cap_add(container_info)) + + def test_compare_cap_add_unprivileged_with_user_caps(self): + container_info = {'HostConfig': dict( + CapAdd=['CAP_NET_ADMIN', 'CAP_AUDIT_WRITE'], + Privileged=False + )} + self.pw = get_PodmanWorker({'cap_add': ['net_admin']}) + self.assertFalse(self.pw.compare_cap_add(container_info)) + + def test_compare_cap_add_privileged_no_audit_write(self): + container_info = {'HostConfig': dict( + CapAdd=['CAP_NET_ADMIN'], + Privileged=True + )} + self.pw = get_PodmanWorker( + {'cap_add': ['net_admin'], 'privileged': True}) + self.assertFalse(self.pw.compare_cap_add(container_info)) + + def test_compare_cap_add_format_normalization(self): + container_info = {'HostConfig': dict( + CapAdd=['CAP_SYS_ADMIN', 'CAP_AUDIT_WRITE'], + Privileged=False + )} + self.pw = get_PodmanWorker({'cap_add': ['sys_admin']}) + self.assertFalse(self.pw.compare_cap_add(container_info)) + + def test_compare_cap_add_podman_bug_workaround(self): + container_info = {'HostConfig': dict( + CapAdd=[], + Privileged=False + )} + self.pw = get_PodmanWorker({'cap_add': []}) self.assertFalse(self.pw.compare_cap_add(container_info)) - def test_compare_cap_add_pos(self): - container_info = {'HostConfig': dict(CapAdd=['data1'])} - self.pw = get_PodmanWorker({'cap_add': ['data2']}) + def test_compare_cap_add_difference_detected(self): + container_info = {'HostConfig': dict( + CapAdd=['CAP_NET_ADMIN', 'CAP_AUDIT_WRITE'], + Privileged=False + )} + self.pw = get_PodmanWorker({'cap_add': ['sys_admin']}) self.assertTrue(self.pw.compare_cap_add(container_info)) + def test_compare_cap_add_mixed_case_formats(self): + container_info = {'HostConfig': dict( + CapAdd=['CAP_SYS_ADMIN', 'CAP_NET_ADMIN', 'CAP_AUDIT_WRITE'], + Privileged=False + )} + self.pw = get_PodmanWorker( + {'cap_add': ['SYS_ADMIN', 'cap_net_admin']}) + self.assertFalse(self.pw.compare_cap_add(container_info)) + + def test_compare_cap_add_empty_current(self): + container_info = {'HostConfig': dict( + CapAdd=None, + Privileged=False + )} + self.pw = get_PodmanWorker({'cap_add': []}) + self.assertFalse(self.pw.compare_cap_add(container_info)) + def test_compare_ipc_mode_neg(self): container_info = {'HostConfig': dict(IpcMode='data')} self.pw = get_PodmanWorker({'ipc_mode': 'data'}) @@ -1233,19 +1305,149 @@ class TestAttrComp(base.BaseTestCase): def test_compare_volumes_neg(self): container_info = { 'Config': dict(Volumes=['/var/log/kolla/']), - 'HostConfig': dict(Binds=['kolla_logs:/var/log/kolla/:rw'])} - self.pw = get_PodmanWorker( - {'volumes': ['kolla_logs:/var/log/kolla/:rw']}) - + 'HostConfig': dict(Binds=[ + 'kolla_logs:/var/log/kolla/:rw,rprivate,nosuid,nodev,rbind' + ]) + } + self.pw = get_PodmanWorker({ + 'volumes': ['kolla_logs:/var/log/kolla/'] + }) self.assertFalse(self.pw.compare_volumes(container_info)) def test_compare_volumes_pos(self): container_info = { 'Config': dict(Volumes=['/var/log/kolla/']), - 'HostConfig': dict(Binds=['kolla_logs:/var/log/kolla/:rw'])} - self.pw = get_PodmanWorker( - {'volumes': ['/dev/:/dev/:rw']}) + 'HostConfig': dict(Binds=[ + 'kolla_logs:/var/log/kolla/:ro,rprivate,nosuid,nodev,rbind' + ]) + } + self.pw = get_PodmanWorker({ + 'volumes': ['kolla_logs:/var/log/kolla/'] + }) + self.assertTrue(self.pw.compare_volumes(container_info)) + + def test_compare_volumes_empty_add(self): + container_info = { + 'Config': dict(Volumes=[]), + 'HostConfig': dict(Binds=[]) + } + self.pw = get_PodmanWorker({ + 'volumes': ['kolla_logs:/var/log/kolla/'] + }) + self.assertTrue(self.pw.compare_volumes(container_info)) + + def test_compare_volumes_empty_del(self): + container_info = { + 'Config': dict(Volumes=['/var/log/kolla/']), + 'HostConfig': dict(Binds=[ + 'kolla_logs:/var/log/kolla/:ro,rprivate,nosuid,nodev,rbind' + ]) + } + self.pw = get_PodmanWorker({ + 'volumes': [] + }) + self.assertTrue(self.pw.compare_volumes(container_info)) + + def test_compare_volumes_noexec_default(self): + container_info = { + 'Config': dict(Volumes=['/proc/', '/run/libvirt', '/sys/']), + 'HostConfig': dict(Binds=[ + '/proc/:/proc/:rw,shared,rprivate,nosuid,nodev,noexec,rbind', + '/run/libvirt:/run/libvirt:rw,nosuid,nodev,noexec,rbind', + '/sys/:/sys/:rw,rprivate,nosuid,nodev,noexec,rbind', + ]) + } + self.pw = get_PodmanWorker({ + 'volumes': [ + '/proc/:/proc/:shared', + '/run/libvirt:/run/libvirt:rprivate', + '/sys/:/sys/:rprivate' + ] + }) + self.assertFalse(self.pw.compare_volumes(container_info)) + + def test_compare_volumes_shared_vs_rw(self): + container_info = { + 'Config': dict(Volumes=['/run/libvirt/']), + 'HostConfig': dict(Binds=[ + '/run/libvirt:/run/libvirt:rw,rprivate,nosuid,nodev,rbind' + ]) + } + self.pw = get_PodmanWorker({ + 'volumes': ['/run/libvirt:/run/libvirt:shared'] + }) + self.assertTrue(self.pw.compare_volumes(container_info)) + + def test_compare_volumes_implicit_rw_both_sides(self): + container_info = { + 'Config': dict(Volumes=['/dev/shm/']), # nosec + 'HostConfig': dict(Binds=[ + '/dev/shm:/dev/shm:rprivate,nosuid,nodev,rbind' # nosec + ]) + } + self.pw = get_PodmanWorker({ + 'volumes': ['/dev/shm:/dev/shm'] # nosec + }) + self.assertFalse(self.pw.compare_volumes(container_info)) + + def test_compare_volumes_explicit_rw_vs_implicit(self): + container_info = { + 'Config': dict(Volumes=['/data/']), + 'HostConfig': dict(Binds=[ + '/host/data:/data:rprivate,nosuid,nodev,rbind' + ]) + } + self.pw = get_PodmanWorker({ + 'volumes': ['/host/data:/data:rw'] + }) + self.assertFalse(self.pw.compare_volumes(container_info)) + + def test_compare_volumes_var_run_noexec(self): + container_info = { + 'Config': dict(Volumes=['/var/run/libvirt/']), + 'HostConfig': dict(Binds=[ + '/var/run/libvirt:/var/run/libvirt:' + 'rw,rprivate,nosuid,nodev,noexec,rbind' + ]) + } + self.pw = get_PodmanWorker({ + 'volumes': ['/var/run/libvirt:/var/run/libvirt'] + }) + self.assertFalse(self.pw.compare_volumes(container_info)) + + def test_compare_volumes_multiple_binds(self): + container_info = { + 'Config': dict(Volumes=[ # nosec + '/var/log/kolla/', '/etc/kolla/', '/dev/shm/']), + 'HostConfig': dict(Binds=[ + 'kolla_logs:/var/log/kolla/:rw,rprivate,nosuid,nodev,rbind', + '/etc/kolla:/etc/kolla:ro,rprivate,nosuid,nodev,rbind', + '/dev/shm:/dev/shm:rprivate,nosuid,nodev,rbind' # nosec + ]) + } + self.pw = get_PodmanWorker({ + 'volumes': [ + 'kolla_logs:/var/log/kolla/', + '/etc/kolla:/etc/kolla:ro', + '/dev/shm:/dev/shm' # nosec + ] + }) + self.assertFalse(self.pw.compare_volumes(container_info)) + def test_compare_volumes_multiple_binds_one_diff(self): + container_info = { + 'Config': dict(Volumes=['/var/log/kolla/', '/etc/kolla/']), + 'HostConfig': dict(Binds=[ + 'kolla_logs:/var/log/kolla/:rw,rprivate,nosuid,nodev,rbind', + '/etc/kolla:/etc/kolla:ro,rprivate,nosuid,nodev,rbind' + ]) + } + self.pw = get_PodmanWorker({ + 'volumes': [ + 'kolla_logs:/var/log/kolla/', + '/etc/kolla:/etc/kolla:rw' + ] + }) self.assertTrue(self.pw.compare_volumes(container_info)) def test_compare_environment_neg(self): @@ -1368,27 +1570,93 @@ class TestAttrComp(base.BaseTestCase): def test_compare_ulimits_pos(self): self.fake_data['params']['dimensions'] = { - 'ulimits': {'nofile': {'soft': 131072, 'hard': 131072}}} + 'ulimits': { + 'memlock': {'soft': 67108864, 'hard': 67108864}} + } container_info = dict() container_info['HostConfig'] = { 'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0, 'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0, 'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0, - 'Ulimits': []} + 'Ulimits': [ + {'Name': 'RLIMIT_NOFILE', 'Soft': 1024, 'Hard': 4096}, + {'Name': 'RLIMIT_NPROC', 'Soft': 4096, 'Hard': 4096} + ]} self.pw = get_PodmanWorker(self.fake_data['params']) self.assertTrue(self.pw.compare_dimensions(container_info)) def test_compare_ulimits_neg(self): self.fake_data['params']['dimensions'] = { - 'ulimits': {'nofile': {'soft': 131072, 'hard': 131072}}} - ulimits_nofile = {'Name': 'nofile', - 'Soft': 131072, 'Hard': 131072} + 'ulimits': { + 'memlock': {'soft': 67108864, 'hard': 67108864}} + } + container_info = dict() + container_info['HostConfig'] = { + 'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0, + 'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0, + 'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0, + 'Ulimits': [ + {'Name': 'RLIMIT_NOFILE', 'Soft': 1024, 'Hard': 4096}, + {'Name': 'RLIMIT_NPROC', 'Soft': 4096, 'Hard': 4096}, + {'Name': 'RLIMIT_MEMLOCK', 'Soft': 67108864, 'Hard': 67108864} + ]} + self.pw = get_PodmanWorker(self.fake_data['params']) + self.assertFalse(self.pw.compare_dimensions(container_info)) + + def test_compare_ulimits_ignore_podman_defaults(self): + self.fake_data['params']['dimensions'] = {'ulimits': {}} + container_info = dict() + container_info['HostConfig'] = { + 'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0, + 'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0, + 'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0, + 'Ulimits': [ + # These ulimits are not settable by the user and + # are set by default on every podman container. + # We should ignore them on dimensions check. + {'Name': 'RLIMIT_NOFILE', 'Soft': 1024, 'Hard': 4096}, + {'Name': 'RLIMIT_NPROC', 'Soft': 4096, 'Hard': 4096} + ]} + self.pw = get_PodmanWorker(self.fake_data['params']) + self.assertFalse(self.pw.compare_dimensions(container_info)) + + def test_compare_ulimits_filter_defaults_both_sides(self): + self.fake_data['params']['dimensions'] = { + 'ulimits': { + 'RLIMIT_NOFILE': {'soft': 1048576, 'hard': 1048576}, + 'RLIMIT_NPROC': {'soft': 1048576, 'hard': 1048576} + } + } + container_info = dict() + container_info['HostConfig'] = { + 'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0, + 'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0, + 'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0, + 'Ulimits': [ + {'Name': 'RLIMIT_NOFILE', 'Soft': 1048576, 'Hard': 1048576}, + {'Name': 'RLIMIT_NPROC', 'Soft': 1048576, 'Hard': 1048576} + ]} + self.pw = get_PodmanWorker(self.fake_data['params']) + self.assertFalse(self.pw.compare_dimensions(container_info)) + + def test_compare_ulimits_with_other_limits_and_defaults(self): + self.fake_data['params']['dimensions'] = { + 'ulimits': { + 'RLIMIT_NOFILE': {'soft': 1048576, 'hard': 1048576}, + 'RLIMIT_NPROC': {'soft': 1048576, 'hard': 1048576}, + 'memlock': {'soft': 67108864, 'hard': 67108864} + } + } container_info = dict() container_info['HostConfig'] = { 'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0, 'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0, 'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0, - 'Ulimits': [ulimits_nofile]} + 'Ulimits': [ + {'Name': 'RLIMIT_NOFILE', 'Soft': 1048576, 'Hard': 1048576}, + {'Name': 'RLIMIT_NPROC', 'Soft': 1048576, 'Hard': 1048576}, + {'Name': 'RLIMIT_MEMLOCK', 'Soft': 67108864, 'Hard': 67108864} + ]} self.pw = get_PodmanWorker(self.fake_data['params']) self.assertFalse(self.pw.compare_dimensions(container_info)) diff --git a/tests/templates/globals-default.j2 b/tests/templates/globals-default.j2 index 0b42d36e2..2e72a079a 100644 --- a/tests/templates/globals-default.j2 +++ b/tests/templates/globals-default.j2 @@ -18,10 +18,10 @@ docker_yum_url: "http://{{ zuul_site_mirror_fqdn }}:8080/docker/centos" podman_debug: true podman_registry_mirrors: - {{ infra_dockerhub_mirror }} -{% if need_build_image and is_previous_release %} +{% if need_build_image and is_previous_release %} podman_registry: "primary:4000" podman_registry_insecure: true -{% endif %} +{% endif %} {% else %} docker_debug: true docker_apt_package_pin: "5:28.*" @@ -33,11 +33,11 @@ docker_registry_mirrors: # as docker_registry var is being used both for docker daemon config # - for kolla images build, and kolla-ansible container images sources. # docker_custom_config gets precedence in docker daemon configuration. -{% if need_build_image and is_previous_release %} +{% if need_build_image and is_previous_release %} docker_custom_config: insecure-registries: - primary:4000 -{% endif %} +{% endif %} {% endif %} # MariaDB/Galera - fine tune timeouts @@ -66,8 +66,8 @@ kolla_internal_vip_address: "{{ kolla_internal_vip_address }}" neutron_external_interface: "{{ neutron_external_interface_name }}" openstack_logging_debug: "True" nova_libvirt_logging_debug: "False" -openstack_service_workers: "1" -openstack_service_rpc_workers: "1" +openstack_service_workers: "2" +openstack_service_rpc_workers: "2" {% endif %} {% if need_build_image and not is_previous_release %} @@ -78,16 +78,16 @@ docker_namespace: "lokolla" # see: https://github.com/moby/moby/issues/39033 docker_registry: "primary:4000" docker_registry_insecure: yes -{% if container_engine == 'podman' %} +{% if container_engine == 'podman' %} podman_registry: "primary:4000" podman_registry_insecure: yes -{% endif %} +{% endif %} openstack_tag: "{{ build_image_tag }}" {% else %} docker_namespace: openstack.kolla -{% if docker_image_tag_suffix %} +{% if docker_image_tag_suffix %} openstack_tag_suffix: "{{ docker_image_tag_suffix }}" -{% endif %} +{% endif %} {% endif %} {% if scenario == "zun" %} @@ -118,10 +118,6 @@ enable_barbican: "yes" enable_heat: "yes" # NOTE(yoctozepto): see https://bugs.launchpad.net/kolla-ansible/+bug/1906299 enable_aodh: "yes" -# TODO(gkoper): Remove after G/2026.1 release -{% if is_previous_release %} -enable_redis: "yes" -{% endif %} {% endif %} {% if scenario == "ironic" %} @@ -166,18 +162,18 @@ nova_backend_ceph: "yes" rabbitmq_cluster_partition_handling: "autoheal" rabbitmq_extra_config: cluster_keepalive_interval: 50000 -# TODO(gkoper): Remove after G/2026.1 release -{% if is_previous_release %} +# TODO(bbezak): Remove in H/2026.2 cycle +{% if is_slurp and is_previous_release %} enable_redis: "yes" -{% endif %} +{% endif %} enable_ceph_rgw: "yes" ceph_rgw_hosts: -{% for host in hostvars | reject('equalto', 'localhost') %} +{% for host in hostvars | reject('equalto', 'localhost') %} - host: {{ host }} ip: {{ hostvars[host]['ansible_host'] }} port: 6780 -{% endfor %} +{% endfor %} {% endif %} {% if tls_enabled %} @@ -185,12 +181,12 @@ kolla_enable_tls_external: "yes" kolla_enable_tls_internal: "yes" kolla_copy_ca_into_containers: "yes" kolla_enable_tls_backend: "yes" -{% if base_distro in ["debian", "ubuntu"] %} +{% if base_distro in ["debian", "ubuntu"] %} openstack_cacert: "/etc/ssl/certs/ca-certificates.crt" -{% endif %} -{% if base_distro in ["centos", "rocky"] %} +{% endif %} +{% if base_distro in ["centos", "rocky"] %} openstack_cacert: "/etc/pki/tls/certs/ca-bundle.crt" -{% endif %} +{% endif %} kolla_admin_openrc_cacert: "{% raw %}{{ kolla_certificates_dir }}{% endraw %}/ca/root.crt" rabbitmq_enable_tls: "yes" libvirt_tls: "yes" @@ -204,10 +200,6 @@ enable_octavia: "yes" octavia_provider_drivers: "ovn:OVN provider" octavia_provider_agents: "ovn" neutron_dns_domain: "example.org." -# TODO(gkoper): Remove after G/2026.1 release -{% if is_previous_release %} -enable_redis: "yes" -{% endif %} {% endif %} {% if scenario == "prometheus-opensearch" %} @@ -240,10 +232,6 @@ octavia_amp_flavor: disk: 5 octavia_network_type: "tenant" enable_valkey: "yes" -# TODO(gkoper): Remove after G/2026.1 release -{% if is_previous_release %} -enable_redis: "yes" -{% endif %} {% endif %} {% if groups['all'] | length == 1 %} diff --git a/tests/templates/inventory.j2 b/tests/templates/inventory.j2 index 8441d825e..b5bb76907 100644 --- a/tests/templates/inventory.j2 +++ b/tests/templates/inventory.j2 @@ -7,13 +7,13 @@ [control] {% if scenario == 'masakari' %} -{% for host in hostvars if host in ['primary'] %} +{% for host in hostvars if host in ['primary'] %} {{ host }} ansible_host={{ hostvars[host]['ansible_host'] }} -{% endfor %} +{% endfor %} {% else %} -{% for host in hostvars | reject('equalto', 'localhost') %} +{% for host in hostvars | reject('equalto', 'localhost') %} {{ host }} ansible_host={{ hostvars[host]['ansible_host'] }} -{% endfor %} +{% endfor %} {% endif %} [network:children] @@ -27,13 +27,13 @@ control [compute] {% if scenario == 'masakari' %} -{% for host in hostvars if host in ['ternary1', 'ternary2'] %} +{% for host in hostvars if host in ['ternary1', 'ternary2'] %} {{ host }} ansible_host={{ hostvars[host]['ansible_host'] }} -{% endfor %} +{% endfor %} {% else %} -{% for host in hostvars | reject('equalto', 'localhost') %} +{% for host in hostvars | reject('equalto', 'localhost') %} {{ host }} ansible_host={{ hostvars[host]['ansible_host'] }} -{% endfor %} +{% endfor %} {% endif %} [storage] @@ -52,8 +52,8 @@ control {% endfor %} {% if scenario == 'cells' %} -{% for host in hostvars | reject('equalto', 'localhost') %} -{% set cell_name = 'cell' ~ loop.index %} +{% for host in hostvars | reject('equalto', 'localhost') %} +{% set cell_name = 'cell' ~ loop.index %} [{{ cell_name }}] {{ host }} ansible_host={{ hostvars[host]['ansible_host'] }} mariadb_shard_id={{ loop.index0 % 2 }} @@ -65,7 +65,7 @@ nova_cell_novncproxy_group = {{ cell_name }} nova_novncproxy_port = {{ 6080 + loop.index0 }} nova_cell_database_shard_id = {{ loop.index0 % 2 }} -{% endfor %} +{% endfor %} {% endif %} [baremetal:children] @@ -124,9 +124,9 @@ storage [hacluster] {% for host in hostvars | reject('equalto', 'localhost') %} -{% if host in ['primary', 'secondary'] %} +{% if host in ['primary', 'secondary'] %} {{ host }} ansible_host={{ hostvars[host]['ansible_host'] }} -{% endif %} +{% endif %} {% endfor %} [hacluster-remote:children] diff --git a/tests/templates/nova-compute-overrides.j2 b/tests/templates/nova-compute-overrides.j2 index 7bcbaf11c..032155cca 100644 --- a/tests/templates/nova-compute-overrides.j2 +++ b/tests/templates/nova-compute-overrides.j2 @@ -9,8 +9,8 @@ cpu_model=max # newer than the qemu default of qemu64. Nehalem is apparently the # oldest model that works for x86_64-v2 and is expected to work on # Intel and AMD cpus with kvm or qemu. -{% if virt_type == 'kvm' %} +{% if virt_type == 'kvm' %} cpu_mode = custom cpu_models = Nehalem -{% endif %} +{% endif %} {% endif %} diff --git a/tests/test_kolla_container_facts.py b/tests/test_kolla_container_facts.py index b6a3d8000..d4aedf717 100644 --- a/tests/test_kolla_container_facts.py +++ b/tests/test_kolla_container_facts.py @@ -213,7 +213,7 @@ class TestContainerFacts(base.BaseTestCase): self.dfw.client.containers.get.assert_called_once_with('my_container') self.assertIn('my_container', self.dfw.result['envs']) self.assertNotIn('my_container', self.dfw.result) - self.assertEquals(self.dfw.result['envs']['my_container'], fake_env) + self.assertEqual(self.dfw.result['envs']['my_container'], fake_env) def test_get_containers_env_negative(self): self.dfw = get_DockerFactsWorker({'name': ['fake_container'], diff --git a/tests/test_kolla_toolbox.py b/tests/test_kolla_toolbox.py index 9dca821cc..e170964db 100644 --- a/tests/test_kolla_toolbox.py +++ b/tests/test_kolla_toolbox.py @@ -263,6 +263,53 @@ class TestKollaToolboxMethods(TestKollaToolboxModule): self.assertIn('Ansible JSON output has unexpected format', error.result['msg']) + def test_process_container_output_deprecation(self): + container_output_deprecation = "[DEPRECATION WARNING] Some deprecation" + container_output_json = { + 'custom_stats': {}, + 'global_custom_stats': {}, + 'plays': [ + { + 'tasks': [ + { + 'hosts': { + 'localhost': { + '_ansible_no_log': False, + 'action': 'ping', + 'changed': False, + 'invocation': { + 'module_args': { + 'data': 'pong' + } + }, + 'ping': 'pong' + } + }, + } + ] + } + ], + } + container_encoded_json = json.dumps(container_output_json) + container_output = (str(container_output_deprecation) + + str(container_encoded_json)).encode('utf-8') + + expected_output = { + 'action': 'ping', + 'changed': False, + 'invocation': { + 'module_args': { + 'data': 'pong' + } + }, + 'ping': 'pong' + } + generated_module_output = self.fake_ktbw._process_container_output( + container_output) + + self.assertNotIn('_ansible_no_log', generated_module_output) + self.assertEqual(expected_output, generated_module_output) + def test_process_container_output_success(self): container_output_json = { 'custom_stats': {}, diff --git a/tests/testinfra/test_horizon.py b/tests/testinfra/test_horizon.py index abdb787c6..1f193e383 100644 --- a/tests/testinfra/test_horizon.py +++ b/tests/testinfra/test_horizon.py @@ -33,9 +33,11 @@ with open("/etc/kolla/passwords.yml", 'r') as file: def test_horizon_screenshot(host): firefox_options = webdriver.FirefoxOptions() + selenium_url = host.environment().get( + 'SELENIUM_REMOTE_URL', 'http://localhost:4500/wd/hub') driver = webdriver.Remote( - command_executor='http://localhost:4444/wd/hub', + command_executor=selenium_url, options=firefox_options) horizon_proto = host.environment().get('HORIZON_PROTO') @@ -73,9 +75,11 @@ def test_horizon_screenshot(host): def test_horizon_login(host): firefox_options = webdriver.FirefoxOptions() + selenium_url = host.environment().get( + 'SELENIUM_REMOTE_URL', 'http://localhost:4500/wd/hub') driver = webdriver.Remote( - command_executor='http://localhost:4444/wd/hub', + command_executor=selenium_url, options=firefox_options) horizon_proto = host.environment().get('HORIZON_PROTO') |
