aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rwxr-xr-xtests/check-logs.sh3
-rwxr-xr-xtests/j2lint.py88
-rw-r--r--tests/kolla_container_tests/test_docker_worker.py73
-rw-r--r--tests/kolla_container_tests/test_podman_worker.py364
-rw-r--r--tests/templates/globals-default.j250
-rw-r--r--tests/templates/inventory.j226
-rw-r--r--tests/templates/nova-compute-overrides.j24
-rw-r--r--tests/test_kolla_container_facts.py2
-rw-r--r--tests/test_kolla_toolbox.py47
-rw-r--r--tests/testinfra/test_horizon.py8
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')