Browse Source

Merge "Provision workflow managed/unmanaged node support"

changes/83/770783/1
Zuul 4 months ago
committed by Gerrit Code Review
parent
commit
f5a99b59a0
7 changed files with 303 additions and 5 deletions
  1. +14
    -0
      doc/source/modules/modules-tripleo_unmanaged_populate_environment.rst
  2. +26
    -1
      tripleo_ansible/ansible_plugins/module_utils/baremetal_deploy.py
  3. +6
    -2
      tripleo_ansible/ansible_plugins/modules/tripleo_baremetal_check_existing.py
  4. +179
    -0
      tripleo_ansible/ansible_plugins/modules/tripleo_unmanaged_populate_environment.py
  5. +1
    -0
      tripleo_ansible/playbooks/cli-overcloud-node-provision.yaml
  6. +73
    -0
      tripleo_ansible/tests/modules/test_tripleo_unmanaged_populate_environment.py
  7. +4
    -2
      tripleo_ansible/tests/plugins/module_utils/test_baremetal_deploy.py

+ 14
- 0
doc/source/modules/modules-tripleo_unmanaged_populate_environment.rst View File

@ -0,0 +1,14 @@
===============================================
Module - tripleo_unmanaged_populate_environment
===============================================
This module provides for the following ansible plugin:
* tripleo_unmanaged_populate_environment
.. ansibleautoplugin::
:module: tripleo_ansible/ansible_plugins/modules/tripleo_unmanaged_populate_environment.py
:documentation: true
:examples: true

+ 26
- 1
tripleo_ansible/ansible_plugins/module_utils/baremetal_deploy.py View File

@ -85,6 +85,8 @@ _INSTANCE_SCHEMA = {
'items': {'type': 'string'}
},
'user_name': {'type': 'string'},
'managed': {'type': 'boolean'},
'management_ip': {'type': 'string'},
},
'additionalProperties': False,
}
@ -306,7 +308,12 @@ def check_existing(instances, provisioner, baremetal):
not_found = []
found = []
unmanaged = []
for request in instances:
if not request.get('managed', True):
unmanaged.append(request)
continue
ident = request.get('name', request['hostname'])
try:
@ -346,7 +353,7 @@ def check_existing(instances, provisioner, baremetal):
)
found.append(instance)
return found, not_found
return found, not_found, unmanaged
def populate_environment(instance_uuids, provisioner, environment,
@ -390,7 +397,9 @@ def validate_instances(instances, schema):
jsonschema.validate(instances, schema)
hostnames = set()
names = set()
fixed_ips = set()
for inst in instances:
name = inst.get('hostname', inst.get('name'))
# NOTE(dtantsur): validate image parameters
get_source(inst)
@ -406,6 +415,22 @@ def validate_instances(instances, schema):
inst['name'])
names.add(inst['name'])
inst_ips = {net['fixed_ip'] for net in inst.get('networks', [])
if net.get('fixed_ip')}
if inst_ips.intersection(fixed_ips):
raise ValueError(
'One or more IP address {ips} for Node {name} is requested '
'more than once'.format(
ips=', '.join(inst_ips.intersection(fixed_ips)),
name=name))
fixed_ips.update(inst_ips)
if not inst.get('managed', True):
if not inst_ips and not inst.get('management_ip'):
raise ValueError('Node %s that is managed: false requires '
'either a fixed IP address, or a management '
'ip address' % name)
def validate_roles(roles):
jsonschema.validate(roles, _ROLES_INPUT_SCHEMA)


+ 6
- 2
tripleo_ansible/ansible_plugins/modules/tripleo_baremetal_check_existing.py View File

@ -114,7 +114,7 @@ def main():
provisioner = metalsmith.Provisioner(cloud_region=cloud.config)
try:
found, not_found = bd.check_existing(
found, not_found, pre_provisioned = bd.check_existing(
instances=module.params['instances'],
provisioner=provisioner,
baremetal=cloud.baremetal
@ -126,6 +126,9 @@ def main():
if not_found:
msg += ('Instance(s) %s do not exist. '
% ', '.join(r['hostname'] for r in not_found))
if pre_provisioned:
msg += ('Instance(s) %s are pre-provisioned. '
% ', '.join(r['hostname'] for r in pre_provisioned))
instances = [{
'name': i.node.name or i.uuid,
@ -136,7 +139,8 @@ def main():
changed=False,
msg=msg,
instances=instances,
not_found=not_found
not_found=not_found,
pre_provisioned=pre_provisioned
)
except Exception as e:
module.fail_json(msg=str(e))


+ 179
- 0
tripleo_ansible/ansible_plugins/modules/tripleo_unmanaged_populate_environment.py View File

@ -0,0 +1,179 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2020 OpenStack Foundation
# 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.
import yaml
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.openstack import openstack_full_argument_spec
from ansible.module_utils.openstack import openstack_module_kwargs
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: tripleo_unmanaged_populate_environment
short_description: Add unmanaged node to existing heat environment
version_added: "2.8"
description:
- "Add unmanaged node to existing heat environment"
options:
environment:
description:
- Existing heat environment data to add to
type: dict
default: {}
instances:
description:
- List of unmanaged instances
required: true
type: list
elements: dict
node_port_map:
description:
- Structure with port data mapped by node and network, in the format
returned by the tripleo_overcloud_network_ports module.
type: dict
default: {}
ctlplane_network:
description:
- Name of control plane network
default: ctlplane
type: str
author:
- Harald Jensås <hjensas@redhat.com>
'''
RETURN = '''
parameter_defaults:
FooParam: foo
DeployedServerPortMap:
controller-0-ctlplane:
fixed_ips:
- ip_address': 1.1.1.1
compute-0-ctlplane:
fixed_ips:
- ip_address': 1.1.1.2
instance3-ctlplane:
fixed_ips:
- ip_address': 1.1.1.3
resource_registry:
OS::Fake::Resource: /path/to/fake/resource.yaml
'''
EXAMPLES = '''
- name: Populate environment with network port data
tripleo_unmanaged_populate_environment:
ctlplane_network: ctlplane
environment:
parameter_defaults:
FooParam: foo
DeployedServerPortMap:
instance3-ctlplane:
fixed_ips:
- ip_address': 1.1.1.3
resource_registry:
OS::Fake::Resource: /path/to/fake/resource.yaml
instances:
- hostname: controller-0
managed: false
networks:
- network: ctlplane
fixed_ip: 1.1.1.1
- hostname': compute-0
managed: false
networks:
- network: ctlplane
fixed_ip: 1.1.1.2
node_port_map:
controller-0:
ctlplane:
ip_address: 1.1.1.1
ip_subnet: 1.1.1.1/24
ip_address_uri: 1.1.1.1
compute-0:
ctlplane:
ip_address: 1.1.1.2
ip_subnet: 1.1.1.2/24
ip_address_uri: 1.1.1.2
register: environment
'''
def update_environment(environment, ctlplane_network, node_port_map,
instances):
parameter_defaults = environment.setdefault('parameter_defaults', {})
port_map = parameter_defaults.setdefault('DeployedServerPortMap', {})
for instance in instances:
if instance.get('managed', True):
continue
hostname = instance['hostname']
ip_address = node_port_map[hostname][ctlplane_network]['ip_address']
ctlplane = {}
ctlplane['fixed_ips'] = [{'ip_address': ip_address}]
port_map['%s-%s' % (hostname, ctlplane_network)] = ctlplane
def run_module():
result = dict(
success=False,
changed=False,
error="",
environment={},
)
argument_spec = openstack_full_argument_spec(
**yaml.safe_load(DOCUMENTATION)['options']
)
module = AnsibleModule(
argument_spec,
supports_check_mode=False,
**openstack_module_kwargs()
)
environment = result['environment'] = module.params['environment']
instances = module.params['instances']
node_port_map = module.params['node_port_map']
ctlplane_network = module.params['ctlplane_network']
try:
update_environment(environment, ctlplane_network, node_port_map,
instances)
result['success'] = True
module.exit_json(**result)
except Exception as err:
result['error'] = str(err)
result['msg'] = ("Error overcloud network provision failed!")
module.fail_json(**result)
def main():
run_module()
if __name__ == '__main__':
main()

+ 1
- 0
tripleo_ansible/playbooks/cli-overcloud-node-provision.yaml View File

@ -134,6 +134,7 @@
concurrency: "{{ runtime_concurrency }}"
instances: "{{ baremetal_instances.instances }}"
provisioned_instances: "{{ baremetal_provisioned.instances + baremetal_existing.instances }}"
hostname_role_map: "{{ baremetal_instances.hostname_role_map }}"
state: present
register: instance_network_ports
when: manage_network_ports|default(false)


+ 73
- 0
tripleo_ansible/tests/modules/test_tripleo_unmanaged_populate_environment.py View File

@ -0,0 +1,73 @@
# Copyright 2020 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.
import copy
from tripleo_ansible.ansible_plugins.modules import (
tripleo_unmanaged_populate_environment as plugin)
from tripleo_ansible.tests import base as tests_base
FAKE_INSTANCES = [
{'hostname': 'instance1',
'managed': False,
'networks': [{'network': 'ctlplane', 'fixed_ip': '1.1.1.1'}]},
{'hostname': 'instance2',
'managed': False,
'networks': [{'network': 'ctlplane', 'fixed_ip': '1.1.1.2'}]},
{'hostname': 'instance3',
'networks': [{'network': 'ctlplane', 'vif': True}]},
]
FAKE_ENVIRONMENT = {
'parameter_defaults': {
'FooParam': 'foo',
'DeployedServerPortMap': {
'instance3-ctlplane': {
'fixed_ips': [{'ip_address': '1.1.1.3'}]
}
}
},
'resource_registry': {
'OS::Fake::Resource': '/path/to/fake/resource.yaml'
},
}
FAKE_NODE_PORT_MAP = {
'instance1': {
'ctlplane': {'ip_address': '1.1.1.1'}
},
'instance2': {
'ctlplane': {'ip_address': '1.1.1.2'}
},
'instance3': {
'ctlplane': {'ip_address': '1.1.1.3'}
},
}
class TestTripleoOvercloudNetworkPorts(tests_base.TestCase):
def test_update_environment(self):
env = copy.deepcopy(FAKE_ENVIRONMENT)
plugin.update_environment(env, 'ctlplane', FAKE_NODE_PORT_MAP,
FAKE_INSTANCES)
expected = copy.deepcopy(FAKE_ENVIRONMENT)
expected['parameter_defaults']['DeployedServerPortMap'].update(
{'instance1-ctlplane': {'fixed_ips': [{'ip_address': '1.1.1.1'}]},
'instance2-ctlplane': {'fixed_ips': [{'ip_address': '1.1.1.2'}]},
}
)
self.assertEqual(expected, env)

+ 4
- 2
tripleo_ansible/tests/plugins/module_utils/test_baremetal_deploy.py View File

@ -957,7 +957,8 @@ class TestCheckExistingInstances(base.TestCase):
metalsmith.exceptions.Error(""),
existing,
]
found, not_found = bd.check_existing(instances, pr, baremetal)
found, not_found, unmanaged = bd.check_existing(instances, pr,
baremetal)
self.assertEqual([existing], found)
self.assertEqual([{
@ -986,7 +987,8 @@ class TestCheckExistingInstances(base.TestCase):
existing.uuid = 'aaaa'
pr.show_instance.return_value = existing
found, not_found = bd.check_existing(instances, pr, baremetal)
found, not_found, unmanaged = bd.check_existing(instances, pr,
baremetal)
baremetal.create_allocation.assert_called_once_with(
name='host2', node='server2', resource_class='compute')


Loading…
Cancel
Save