Skip to content

Commit 6d1dd92

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Bump up Ansible supported versions to 11.x/12.x"
2 parents 6fc7628 + 2f84565 commit 6d1dd92

File tree

20 files changed

+219
-56
lines changed

20 files changed

+219
-56
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright (c) 2025 StackHPC Ltd.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
__metaclass__ = type
16+
17+
import kayobe.plugins.action.template_content
18+
19+
ActionModule = kayobe.plugins.action.template_content.ActionModule

ansible/kolla-ansible.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
kolla_ansible_passwords_path: "{{ kayobe_env_config_path }}/kolla/passwords.yml"
9494
kolla_overcloud_inventory_search_paths_static:
9595
- "{{ kayobe_config_path }}"
96-
kolla_overcloud_inventory_search_paths: "{{ kolla_overcloud_inventory_search_paths_static + kayobe_env_search_paths }}"
96+
kolla_overcloud_inventory_search_paths: "{{ kolla_overcloud_inventory_search_paths_static + kayobe_env_search_paths | default([]) }}"
9797
kolla_ansible_certificates_path: "{{ kayobe_env_config_path }}/kolla/certificates"
9898
kolla_inspector_dhcp_pool_start: "{{ inspection_net_name | net_inspection_allocation_pool_start }}"
9999
kolla_inspector_dhcp_pool_end: "{{ inspection_net_name | net_inspection_allocation_pool_end }}"
@@ -103,7 +103,7 @@
103103
kolla_libvirt_tls: "{{ compute_libvirt_enable_tls | bool }}"
104104
kolla_globals_paths_static:
105105
- "{{ kayobe_config_path }}"
106-
kolla_globals_paths_extra: "{{ kolla_globals_paths_static + kayobe_env_search_paths }}"
106+
kolla_globals_paths_extra: "{{ kolla_globals_paths_static + kayobe_env_search_paths | default([]) }}"
107107
kolla_ironic_inspector_host: "{{ groups[controller_ironic_inspector_group][0] if groups[controller_ironic_inspector_group] | length > 0 else '' }}"
108108

109109
- name: Generate Kolla Ansible host vars for the seed host

ansible/roles/kolla-ansible/defaults/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ kolla_ansible_venv_extra_requirements: []
2626
# tested code. Changes to this limit should be tested. It is possible to only
2727
# install ansible-core by setting kolla_ansible_venv_ansible to None.
2828
kolla_ansible_venv_ansible:
29-
kolla_ansible_venv_ansible_core: 'ansible-core>=2.17,<2.19'
29+
kolla_ansible_venv_ansible_core: 'ansible-core>=2.18,<2.20'
3030

3131
# Path to a requirements.yml file for Ansible collections.
3232
kolla_ansible_requirements_yml: "{{ kolla_ansible_venv }}/share/kolla-ansible/requirements.yml"

ansible/roles/kolla-ansible/tasks/install.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@
141141
- "{{ kolla_ansible_venv_ansible_core }}"
142142
- "{{ kolla_ansible_venv_ansible }}"
143143
pip:
144-
name: "{{ (kolla_ansible_packages + kolla_ansible_venv_extra_requirements) | select | list }}"
144+
name: "{{ (kolla_ansible_packages | default([]) + kolla_ansible_venv_extra_requirements | default([])) | select | list }}"
145145
state: latest
146146
extra_args: "{% if kolla_upper_constraints_file %}-c {{ kolla_upper_constraints_file }}{% endif %}"
147147
virtualenv: "{{ kolla_ansible_venv }}"

ansible/roles/kolla-ansible/tests/test-defaults.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
- block:
1212
- name: Test the kolla-ansible role with default values
1313
include_role:
14-
name: ../../kolla-ansible
14+
name: "{{ playbook_dir }}/.."
1515
vars:
1616
kolla_ansible_source_path: "{{ temp_path }}/src"
1717
kolla_ansible_ctl_install_type: "source"

ansible/roles/kolla-openstack/tasks/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,11 @@
119119
params:
120120
content: |
121121
{%- for path in item.sources -%}
122-
{{ lookup('template', path) }}
122+
{{ lookup('file', path) }}
123123
{%- endfor -%}
124124
dest: "{{ item.dest }}"
125125
mode: 0640
126-
copy: "{{ params | combine(item.params) }}"
126+
template_content: "{{ params | combine(item.params) }}"
127127
with_items: "{{ kolla_custom_config_info.concat }}"
128128

129129
- name: Ensure unnecessary extra configuration files are absent

kayobe/ansible.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@
2121
import sys
2222
import tempfile
2323

24-
from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
24+
# TODO(dougszu): Backwards compatibility for Ansible 11. This exception
25+
# handler can be removed in the G cycle.
26+
try:
27+
from ansible.parsing.vault import EncryptedString
28+
except ImportError:
29+
# Ansible 11
30+
from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
31+
EncryptedString = AnsibleVaultEncryptedUnicode
2532

2633
from kayobe import exception
2734
from kayobe import utils
@@ -222,6 +229,9 @@ def _get_environment(parsed_args, external_playbook=False):
222229
"""Return an environment dict for executing an Ansible playbook."""
223230
env = os.environ.copy()
224231
vault.update_environment(parsed_args, env)
232+
# TODO(wszusmki): Kayobe still uses broken conditions. Work on fixing these
233+
# and remove when that work is complete.
234+
env.setdefault("ANSIBLE_ALLOW_BROKEN_CONDITIONALS", "true")
225235
# If the configuration path has been specified via --config-path, ensure
226236
# the environment variable is set, so that it can be referenced by
227237
# playbooks.
@@ -340,7 +350,7 @@ def run_playbook(parsed_args, playbook, *args, **kwargs):
340350

341351
def _sanitise_hostvar(var):
342352
"""Sanitise a host variable."""
343-
if isinstance(var, AnsibleVaultEncryptedUnicode):
353+
if isinstance(var, EncryptedString):
344354
return "******"
345355
# Recursively sanitise dicts and lists.
346356
if isinstance(var, dict):

kayobe/plugins/action/kolla_ansible_host_vars.py

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@
1414

1515
from ansible.plugins.action import ActionBase
1616

17+
# TODO(dougszu): From Ansible 12 onwards we must explicitly trust templates.
18+
# Since this feature is not supported in previous releases, we define a
19+
# noop method here for backwards compatibility. This can be removed in the
20+
# G cycle.
21+
try:
22+
from ansible.template import trust_as_template
23+
except ImportError:
24+
def trust_as_template(template):
25+
return template
26+
1727

1828
class ConfigError(Exception):
1929
pass
@@ -28,6 +38,11 @@ class ActionModule(ActionBase):
2838

2939
TRANSFERS_FILES = False
3040

41+
def trusted_template(self, input):
42+
# Mark all input as trusted.
43+
trusted_input = trust_as_template(input)
44+
return self._templar.template(trusted_input)
45+
3146
def run(self, tmp=None, task_vars=None):
3247
if task_vars is None:
3348
task_vars = dict()
@@ -97,11 +112,11 @@ def _run(self, interfaces, external_networks):
97112
def _get_interface_fact(self, net_name, required, description):
98113
# Check whether the network is mapped to this host.
99114
condition = "{{ '%s' in network_interfaces }}" % net_name
100-
condition = self._templar.template(condition)
115+
condition = self.trusted_template(condition)
101116
if condition:
102117
# Get the network interface for this network.
103118
iface = ("{{ '%s' | net_interface }}" % net_name)
104-
iface = self._templar.template(iface)
119+
iface = self.trusted_template(iface)
105120
if required and not iface:
106121
msg = ("Required network '%s' (%s) does not have an interface "
107122
"configured for this host" % (net_name, description))
@@ -114,20 +129,20 @@ def _get_interface_fact(self, net_name, required, description):
114129

115130
def _get_external_interface(self, net_name, required):
116131
condition = "{{ '%s' in network_interfaces }}" % net_name
117-
condition = self._templar.template(condition)
132+
condition = self.trusted_template(condition)
118133
if condition:
119-
iface = self._templar.template("{{ '%s' | net_interface }}" %
120-
net_name)
134+
iface = self.trusted_template("{{ '%s' | net_interface }}" %
135+
net_name)
121136
if iface:
122137
# When these networks are VLANs, we need to use the
123138
# underlying tagged bridge interface rather than the
124139
# untagged interface. We therefore strip the .<vlan> suffix
125140
# of the interface name. We use a union here as a single
126141
# tagged interface may be shared between these networks.
127-
vlan = self._templar.template("{{ '%s' | net_vlan }}" %
128-
net_name)
129-
parent = self._templar.template("{{ '%s' | net_parent }}" %
130-
net_name)
142+
vlan = self.trusted_template("{{ '%s' | net_vlan }}" %
143+
net_name)
144+
parent = self.trusted_template("{{ '%s' | net_parent }}" %
145+
net_name)
131146
if vlan and parent:
132147
iface = parent
133148
elif vlan and iface.endswith(".%s" % vlan):
@@ -146,15 +161,15 @@ def _get_external_interface_facts(self, external_interfaces):
146161
neutron_external_interfaces = []
147162
neutron_physical_networks = []
148163
missing_physical_networks = []
149-
bridge_suffix = self._templar.template(
164+
bridge_suffix = self.trusted_template(
150165
"{{ network_bridge_suffix_ovs }}")
151-
patch_prefix = self._templar.template("{{ network_patch_prefix }}")
152-
patch_suffix = self._templar.template("{{ network_patch_suffix_ovs }}")
166+
patch_prefix = self.trusted_template("{{ network_patch_prefix }}")
167+
patch_suffix = self.trusted_template("{{ network_patch_suffix_ovs }}")
153168
for interface, iface_networks in external_interfaces.items():
154169
is_bridge = ("{{ '%s' in (network_interfaces |"
155170
"net_select_bridges |"
156171
"map('net_interface')) }}" % interface)
157-
is_bridge = self._templar.template(is_bridge)
172+
is_bridge = self.trusted_template(is_bridge)
158173
neutron_bridge_names.append(interface + bridge_suffix)
159174
# For a bridge, use a veth pair connected to the bridge. Otherwise
160175
# use the interface directly.
@@ -171,7 +186,7 @@ def _get_external_interface_facts(self, external_interfaces):
171186
# attribute set, and if so, whether they are consistent.
172187
iface_physical_networks = []
173188
for iface_network in iface_networks:
174-
physical_network = self._templar.template(
189+
physical_network = self.trusted_template(
175190
"{{ '%s' | net_physical_network }}" % iface_network)
176191
if (physical_network and
177192
physical_network not in iface_physical_networks):

kayobe/plugins/action/merge_configs.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,21 @@
2424

2525
from ansible import constants
2626
from ansible.plugins import action
27+
# TODO(dougszu): From Ansible 12 onwards we must explicitly trust templates.
28+
# Since this feature is not supported in previous releases, we define a
29+
# noop method here for backwards compatibility. This can be removed in the
30+
# G cycle.
31+
try:
32+
from ansible.template import trust_as_template
33+
except ImportError:
34+
def trust_as_template(template):
35+
return template
36+
2737
from io import StringIO
2838

2939
from oslo_config import iniparser
3040

41+
3142
_ORPHAN_SECTION = 'TEMPORARY_ORPHAN_VARIABLE_SECTION'
3243

3344
DOCUMENTATION = '''
@@ -154,7 +165,7 @@ def read_config(self, source, config):
154165
# Only use config if present
155166
if os.access(source, os.R_OK):
156167
with open(source, 'r') as f:
157-
template_data = f.read()
168+
template_data = trust_as_template(f.read())
158169

159170
# set search path to mimic 'template' module behavior
160171
searchpath = [

kayobe/plugins/action/merge_yaml.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@
2727
from ansible import errors as ansible_errors
2828
from ansible.plugins import action
2929

30+
# TODO(dougszu): From Ansible 12 onwards we must explicitly trust templates.
31+
# Since this feature is not supported in previous releases, we define a
32+
# noop method here for backwards compatibility. This can be removed in the
33+
# G cycle.
34+
try:
35+
from ansible.template import trust_as_template
36+
except ImportError:
37+
def trust_as_template(template):
38+
return template
39+
3040
DOCUMENTATION = '''
3141
---
3242
module: merge_yaml
@@ -95,7 +105,7 @@ def read_config(self, source):
95105
# Only use config if present
96106
if source and os.access(source, os.R_OK):
97107
with open(source, 'r') as f:
98-
template_data = f.read()
108+
template_data = trust_as_template(f.read())
99109

100110
# set search path to mimic 'template' module behavior
101111
searchpath = [

0 commit comments

Comments
 (0)