Provision VIPs for ceph related services

This change adds a new task within cli-deployed-ceph that will be
triggered by tripleoclient when --ceph-vip option is set.
The extra_var input file defines the mapping between the ceph services
and their network, and produces (as output) the VIPs associated to the
specified daemons.
It uses the improved version of "tripleo_service_vip" ansible module
that now supports an output path instead only a playbook dir, and is
able to return a payload (the generated data map) that can be used by
other tasks: this ensures we have more control over the provided input
and output.

Change-Id: I5c2e5caa1579af5cf206633447b92e8fdffdda16
This commit is contained in:
Francesco Pantano 2022-01-20 14:37:43 +01:00
parent 8378ac7ae4
commit 2636e84c41
No known key found for this signature in database
GPG Key ID: 0458D4D1F41BD75C
5 changed files with 134 additions and 15 deletions

View File

@ -50,6 +50,11 @@ options:
- The path to the directory of the playbook that was passed to the
ansible-playbook command line.
type: str
render_path:
description:
- The output path to the file that will be produced by executing this
module.
type: str
stack_name:
description:
- Name of the overcloud stack which will be deployed on these instances
@ -197,16 +202,18 @@ def validate_service_vip_vars_file(service_vip_var_file):
service_vip_var_file))
def write_vars_file(port, service, playbook_dir):
def write_vars_file(port, service, playbook_dir, out=None):
ips = [x['ip_address'] for x in port.fixed_ips]
if len(ips) == 1:
ips = ips[0]
playbook_dir_path = os.path.abspath(playbook_dir)
network_data_v2.validate_playbook_dir(playbook_dir)
service_vip_var_file = os.path.join(playbook_dir_path,
'service_vip_vars.yaml')
if out is not None:
service_vip_var_file = os.path.abspath(out)
else:
playbook_dir_path = os.path.abspath(playbook_dir)
network_data_v2.validate_playbook_dir(playbook_dir)
service_vip_var_file = os.path.join(playbook_dir_path,
'service_vip_vars.yaml')
if not os.path.exists(service_vip_var_file):
data = dict()
@ -219,6 +226,8 @@ def write_vars_file(port, service, playbook_dir):
with open(service_vip_var_file, 'w') as f:
f.write(yaml.safe_dump(data, default_flow_style=False))
return data
def use_neutron(conn, stack, service, network, fixed_ips):
@ -273,7 +282,7 @@ def delete_service_vip(module, stack, service='all'):
def create_service_vip(module, stack, service, network, fixed_ips,
playbook_dir):
playbook_dir, out=None):
_use_neutron = True
for fixed_ip in fixed_ips:
if ('use_neutron', False) in fixed_ip.items():
@ -286,7 +295,7 @@ def create_service_vip(module, stack, service, network, fixed_ips,
else:
port = use_fake(service, fixed_ips)
write_vars_file(port, service, playbook_dir)
return write_vars_file(port, service, playbook_dir, out)
def run_module():
@ -310,7 +319,14 @@ def run_module():
state = module.params.get('state')
service = module.params.get('service_name') or 'all'
out = module.params.get('render_path', None)
playbook_dir = module.params.get('playbook_dir', None)
try:
if out is None and playbook_dir is None:
raise Exception("Provide a playbook_dir or an output path file.")
if state == 'present' and service == 'all':
raise Exception("Provide service_name for service_vip creation.")
@ -319,16 +335,17 @@ def run_module():
else:
network = module.params['network']
fixed_ips = module.params.get('fixed_ips', [])
playbook_dir = module.params['playbook_dir']
create_service_vip(module, stack, service, network, fixed_ips,
playbook_dir)
data = create_service_vip(module, stack, service, network, fixed_ips,
playbook_dir, out)
result['changed'] = True
result['success'] = True
result['data'] = data
module.exit_json(**result)
except Exception as err:
result['error'] = str(err)
result['msg'] = ('ERROR: Failed creating/deleting service virtual IP!'
' {}'.format(err))
result['data'] = {}
module.fail_json(**result)

View File

@ -182,6 +182,14 @@
name: tripleo_cephadm
tasks_from: bootstrap
- name: Prepare Ceph VIPs
import_role:
name: tripleo_cephadm
tasks_from: ceph_vip
delegate_to: localhost
when:
- tripleo_cephadm_ha_services_path is defined
- name: Apply Ceph spec
import_role:
name: tripleo_cephadm

View File

@ -69,3 +69,5 @@ tripleo_cephadm_rbd_trash_interval: 15
tripleo_cephadm_apply_ceph_conf_overrides_on_update: false
tripleo_cephadm_standalone: false
tripleo_cephadm_single_host_defaults: false
tripleo_cephadm_ha_services_path: "/home/stack/ceph_services.yaml"
tripleo_cephadm_vip_path: "/home/stack/ceph_vips.yaml"

View File

@ -0,0 +1,87 @@
---
# Copyright 2022 Red Hat, Inc.
# All Rights Reserved.
#
# 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.
# Assumes the following module is in ANSIBLE_LIBRARY=/usr/share/ansible/library/
# https://github.com/ceph/ceph-ansible/blob/master/library/ceph_pool.py
- fail:
msg: stack_name is a required input
when:
- stack_name is undefined
- fail:
msg: ceph_service_mapping is a required input
when:
- tripleo_cephadm_ha_services_path is undefined
- name: Load Virtual IP Ceph networks data config from file
set_fact:
ceph_ha: "{{ lookup('file', tripleo_cephadm_ha_services_path) | from_yaml }}"
when:
- ceph_ha is undefined
- name: Network/Subnet based Ceph VIPs build
block:
- name: Sanity check on user input
fail:
msg: ERROR, subnet or network missing!
when:
- item.get('network', '') | length == 0
- item.get('subnet', '') | length == 0
loop: "{{ ceph_vip_map.get('ceph_services', {}) }}"
- name: Build Ceph VIPs (subnet)
tripleo_service_vip:
render_path: "{{ render_path }}"
stack_name: "{{ stack_name }}"
service_name: "{{ item.service }}"
network: "{{ item.network }}"
fixed_ips:
- {"subnet": "{{ item.get('subnet', item.network + '_subnet') }}"}
loop: "{{ ceph_vip_map.get('ceph_services', {}) }}"
register: services_subnet
when: not ceph_vip_map.get('fixed')
- name: Fixed IPs based Ceph VIPs build
block:
- name: Sanity check on user input
fail:
msg: ERROR, missing fixed ip_address!
when:
- item.get('ip_address','') | length == 0
loop: "{{ ceph_vip_map.get('ceph_services', {}) }}"
- name: Build Ceph VIPs (fixed_ips)
tripleo_service_vip:
render_path: "{{ render_path }}"
stack_name: "{{ stack_name }}"
service_name: "{{ item.service }}"
network: "{{ item.network }}"
fixed_ips:
- {"ip_address": "{{ item.get('ip_address', None) }}"}
loop: "{{ ceph_vip_map.get('ceph_services', {}) }}"
register: services_fixed
when: ceph_vip_map.get('fixed')
- name: SET data
set_fact:
ceph_vips: |
{% if ceph_vip_map.get('fixed') %}
{% set _len = (services_fixed.results | length | int) -1 %}
{{ services_fixed.results[_len].data }}
{% else %}
{% set _len = (services_subnet.results | length | int) -1 %}
{{ services_subnet.results[_len].data }}
{% endif %}

View File

@ -144,16 +144,21 @@ class TestTripleoServiceVip(tests_base.TestCase):
@mock.patch.object(plugin, '_openstack_cloud_from_module', autospec=True)
def test_create_service_vip(self, mock_ocfm, mock_conn, mock_use_neutron,
mock_write_file):
expected = "{'service': '10.0.0.10'}"
module = mock.Mock()
fixed_ips = [{'ip_address': '10.0.0.10', 'subnet_id': 'subnet_id'}]
mock_ocfm.return_value = None, mock_conn
mock_port = mock.Mock()
mock_use_neutron.return_value = mock_port
plugin.create_service_vip(module, 'overcloud', 'service', 'network',
fixed_ips, '/tmp/dir')
payload = plugin.create_service_vip(module, 'overcloud', 'service', 'network',
fixed_ips, '/tmp/dir')
payload.return_value = "{'service': '10.0.0.10'}"
mock_use_neutron.assert_called_with(mock_conn, 'overcloud', 'service',
'network', fixed_ips)
mock_write_file.assert_called_with(mock_port, 'service', '/tmp/dir')
mock_write_file.assert_called_with(mock_port, 'service', '/tmp/dir', None)
self.assertEqual(expected, payload.return_value)
@mock.patch.object(openstack.connection, 'Connection', autospec=True)
@mock.patch.object(plugin, '_openstack_cloud_from_module', autospec=True)
@ -196,4 +201,4 @@ class TestTripleoServiceVip(tests_base.TestCase):
plugin.create_service_vip(module, 'overcloud', 'service', 'network',
fixed_ips, '/tmp/dir')
mock_use_fake.assert_called_with('service', fixed_ips)
mock_write_file.assert_called_with(mock_port, 'service', '/tmp/dir')
mock_write_file.assert_called_with(mock_port, 'service', '/tmp/dir', None)