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:
parent
8378ac7ae4
commit
2636e84c41
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 %}
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue