Support Ironic inspector in Bifrost container
Adds support for setting which ports to add during inspection and a role for creating introspection rules in inspector.
This commit is contained in:
parent
e7c3e7c94b
commit
b235bcf65a
11
ansible/bifrost-introspection-rules.yml
Normal file
11
ansible/bifrost-introspection-rules.yml
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Ensure introspection rules are registered in Bifrost
|
||||
hosts: seed
|
||||
roles:
|
||||
- role: ironic-inspector-rules
|
||||
ironic_inspector_venv: "{{ ansible_env.PWD }}/shade-venv"
|
||||
# No auth required for Bifrost.
|
||||
ironic_inspector_auth_type: None
|
||||
ironic_inspector_auth: {}
|
||||
ironic_inspector_url: "http://localhost:5050"
|
||||
ironic_inspector_rules: "{{ kolla_bifrost_inspector_rules }}"
|
@ -32,6 +32,16 @@ kolla_bifrost_dib_packages: []
|
||||
# Whether to enable ipmitool-based drivers.
|
||||
kolla_bifrost_enable_ipmitool_drivers: true
|
||||
|
||||
###############################################################################
|
||||
# Ironic Inspector configuration.
|
||||
|
||||
# Which MAC addresses to add as ports during introspection. One of 'all',
|
||||
# 'active' or 'pxe'.
|
||||
kolla_bifrost_inspector_port_addition: "all"
|
||||
|
||||
# List of introspection rules for Bifrost's Ironic Inspector service.
|
||||
kolla_bifrost_inspector_rules: []
|
||||
|
||||
###############################################################################
|
||||
# Inventory configuration.
|
||||
|
||||
|
16
ansible/roles/ironic-inspector-rules/defaults/main.yml
Normal file
16
ansible/roles/ironic-inspector-rules/defaults/main.yml
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
# Path to a directory in which to create a virtualenv.
|
||||
ironic_inspector_venv:
|
||||
|
||||
# Authentication type.
|
||||
ironic_inspector_auth_type:
|
||||
|
||||
# Authentication information.
|
||||
ironic_inspector_auth: {}
|
||||
|
||||
# URL of Ironic Inspector API endpoint.
|
||||
ironic_inspector_url:
|
||||
|
||||
# List of rules which should exist. See the Inspector rules API for details of
|
||||
# parameters available for rules.
|
||||
ironic_inspector_rules: []
|
@ -0,0 +1,159 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.openstack import *
|
||||
|
||||
# Store a list of import errors to report to the user.
|
||||
IMPORT_ERRORS = []
|
||||
try:
|
||||
import ironic_inspector_client
|
||||
except Exception as e:
|
||||
IMPORT_ERRORS.append(e)
|
||||
try:
|
||||
import shade
|
||||
except Exception as e:
|
||||
IMPORT_ERRORS.append(e)
|
||||
|
||||
|
||||
DOCUMENTATION = """
|
||||
module: os_ironic_inspector_rule
|
||||
short_description: Create or destroy an Ironic Inspector rule.
|
||||
author: "Mark Goddard <mark@stackhpc.com>"
|
||||
extends_documentation_fragment: openstack
|
||||
description:
|
||||
- Create or destroy an Ironic inspector rule.
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- State of the rule
|
||||
choices: ["present", "absent"]
|
||||
uuid:
|
||||
description:
|
||||
- Globally unique identifier for the rule.
|
||||
required: false
|
||||
description:
|
||||
description:
|
||||
- Description for the rule.
|
||||
required: false
|
||||
conditions:
|
||||
description:
|
||||
- List of conditions that must be met in order to apply the rule.
|
||||
required: true
|
||||
actions:
|
||||
description:
|
||||
- List of actions to be taken when the conditions are met.
|
||||
required: true
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Ensure that an inspector rule exists.
|
||||
os_ironic_inspector_rule:
|
||||
cloud: "openstack"
|
||||
state: present
|
||||
uuid: "d44666e1-35b3-4f6b-acb0-88ab7052da69"
|
||||
description: Set IPMI username in driver_info if not set
|
||||
conditions:
|
||||
- field: "node://driver_info.ipmi_username"
|
||||
op: "is-empty"
|
||||
actions:
|
||||
- action: "set-attribute"
|
||||
path: "driver_info/ipmi_username"
|
||||
value: "root"
|
||||
"""
|
||||
|
||||
|
||||
def _build_client(module):
|
||||
"""Create and return an Ironic inspector client."""
|
||||
cloud = shade.operator_cloud(**module.params)
|
||||
session = cloud.cloud_config.get_session()
|
||||
client = ironic_inspector_client.v1.ClientV1(
|
||||
inspector_url=module.params['inspector_url'],
|
||||
session=session, region_name=module.params['region_name'])
|
||||
return client
|
||||
|
||||
|
||||
def _ensure_rule_present(module, client):
|
||||
"""Ensure that an inspector rule is present."""
|
||||
if module.params['uuid']:
|
||||
try:
|
||||
rule = client.rules.get(module.params['uuid'])
|
||||
except ironic_inspector_client.ClientError as e:
|
||||
if e.response.status_code != 404:
|
||||
module.fail_json(msg="Failed retrieving Inspector rule %s: %s"
|
||||
% (module.params['uuid'], repr(e)))
|
||||
else:
|
||||
# Check whether the rule differs from the request.
|
||||
keys = ('conditions', 'actions', 'description')
|
||||
for key in keys:
|
||||
if rule[key] != module.params[key]:
|
||||
break
|
||||
else:
|
||||
# Nothing to do - rule exists and is as requested.
|
||||
return False
|
||||
# Rule differs - delete it before recreating.
|
||||
_ensure_rule_absent(module, client)
|
||||
|
||||
client.rules.create(module.params['conditions'], module.params['actions'],
|
||||
module.params['uuid'], module.params['description'])
|
||||
return True
|
||||
|
||||
|
||||
def _ensure_rule_absent(module, client):
|
||||
"""Ensure that an inspector rule is absent."""
|
||||
if not module.params['uuid']:
|
||||
module.fail_json(msg="UUID is required to ensure rules are absent")
|
||||
try:
|
||||
client.rules.delete(module.params['uuid'])
|
||||
except ironic_inspector_client.ClientError as e:
|
||||
# If the rule does not exist, no problem and no change.
|
||||
if e.response.status_code == 404:
|
||||
return False
|
||||
module.fail_json(msg="Failed retrieving Inspector rule %s: %s"
|
||||
% (module.params['uuid'], repr(e)))
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = openstack_full_argument_spec(
|
||||
conditions=dict(type='list', required=True),
|
||||
actions=dict(type='list', required=True),
|
||||
description=dict(required=False),
|
||||
uuid=dict(required=False),
|
||||
state=dict(required=False, default='present',
|
||||
choices=['present', 'absent']),
|
||||
inspector_url=dict(required=False),
|
||||
)
|
||||
module_kwargs = openstack_module_kwargs()
|
||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||
|
||||
# Fail if there were any exceptions when importing modules.
|
||||
if IMPORT_ERRORS:
|
||||
module.fail_json(msg="Import errors: %s" %
|
||||
", ".join([repr(e) for e in IMPORT_ERRORS]))
|
||||
|
||||
if (module.params['auth_type'] in [None, 'None'] and
|
||||
module.params['inspector_url'] is None):
|
||||
module.fail_json(msg="Authentication appears disabled, please "
|
||||
"define an inspector_url parameter")
|
||||
|
||||
if (module.params['inspector_url'] and
|
||||
module.params['auth_type'] in [None, 'None']):
|
||||
module.params['auth'] = dict(
|
||||
endpoint=module.params['inspector_url']
|
||||
)
|
||||
|
||||
try:
|
||||
client = _build_client(module)
|
||||
if module.params["state"] == "present":
|
||||
changed = _ensure_rule_present(module, client)
|
||||
else:
|
||||
changed = _ensure_rule_absent(module, client)
|
||||
except Exception as e:
|
||||
module.fail_json(msg="Failed to configure Ironic Inspector rule: %s" %
|
||||
repr(e))
|
||||
else:
|
||||
module.exit_json(changed=changed)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
50
ansible/roles/ironic-inspector-rules/tasks/main.yml
Normal file
50
ansible/roles/ironic-inspector-rules/tasks/main.yml
Normal file
@ -0,0 +1,50 @@
|
||||
---
|
||||
- name: Ensure required packages are installed
|
||||
yum:
|
||||
name: "{{ item }}"
|
||||
state: installed
|
||||
become: True
|
||||
with_items:
|
||||
- python-devel
|
||||
- python-pip
|
||||
- python-virtualenv
|
||||
|
||||
- name: Ensure the latest version of pip is installed
|
||||
pip:
|
||||
name: "{{ item.name }}"
|
||||
state: latest
|
||||
virtualenv: "{{ ironic_inspector_venv }}"
|
||||
with_items:
|
||||
- { name: pip }
|
||||
|
||||
- name: Ensure required Python packages are installed
|
||||
pip:
|
||||
name: "{{ item.name }}"
|
||||
version: "{{ item.version | default(omit) }}"
|
||||
state: present
|
||||
virtualenv: "{{ ironic_inspector_venv }}"
|
||||
with_items:
|
||||
- name: python-ironic-inspector-client
|
||||
- name: shade
|
||||
|
||||
- name: Set a fact to ensure Ansible uses the python interpreter in the virtualenv
|
||||
set_fact:
|
||||
ansible_python_interpreter: "{{ ironic_inspector_venv }}/bin/python"
|
||||
|
||||
- name: Ensure introspection rules exist
|
||||
os_ironic_inspector_rule:
|
||||
auth_type: "{{ ironic_inspector_auth_type }}"
|
||||
auth: "{{ ironic_inspector_auth }}"
|
||||
conditions: "{{ item.conditions }}"
|
||||
actions: "{{ item.actions }}"
|
||||
description: "{{ item.description | default(omit) }}"
|
||||
uuid: "{{ item.uuid | default(item.description | to_uuid) | default(omit) }}"
|
||||
state: present
|
||||
inspector_url: "{{ ironic_inspector_url }}"
|
||||
with_items: "{{ ironic_inspector_rules }}"
|
||||
|
||||
# This variable is unset before we set it, and it does not appear to be
|
||||
# possible to unset a variable in Ansible.
|
||||
- name: Set a fact to reset the Ansible python interpreter
|
||||
set_fact:
|
||||
ansible_python_interpreter: /usr/bin/python
|
@ -42,6 +42,10 @@ kolla_bifrost_dnsmasq_dns_servers: []
|
||||
# DNS domain provided to nodes via DHCP.
|
||||
kolla_bifrost_domain:
|
||||
|
||||
# Which MAC addresses to add as ports during introspection. One of 'all',
|
||||
# 'active' or 'pxe'.
|
||||
kolla_bifrost_inspector_port_addition:
|
||||
|
||||
# Server inventory to be configured in {{ kolla_node_custom_config_path }}/bifrost/servers.yml.
|
||||
kolla_bifrost_servers: {}
|
||||
|
||||
|
@ -27,6 +27,12 @@ dnsmasq_dns_servers: "{{ kolla_bifrost_dnsmasq_dns_servers | join(',') }}"
|
||||
domain: "{{ kolla_bifrost_domain }}"
|
||||
{% endif %}
|
||||
|
||||
{% if kolla_bifrost_inspector_port_addition %}
|
||||
# Which MAC addresses to add as ports during introspection. One of 'all',
|
||||
# 'active' or 'pxe'.
|
||||
inspector_port_addition: "{{ kolla_bifrost_inspector_port_addition }}"
|
||||
{% endif %}
|
||||
|
||||
{% if kolla_bifrost_extra_globals %}
|
||||
###############################################################################
|
||||
# Extra configuration
|
||||
|
@ -28,6 +28,16 @@
|
||||
# Whether to enable ipmitool-based drivers.
|
||||
#kolla_bifrost_enable_ipmitool_drivers:
|
||||
|
||||
###############################################################################
|
||||
# Ironic Inspector configuration.
|
||||
|
||||
# Which MAC addresses to add as ports during introspection. One of 'all',
|
||||
# 'active' or 'pxe'.
|
||||
#kolla_bifrost_inspector_port_addition:
|
||||
|
||||
# List of introspection rules for Bifrost's Ironic Inspector service.
|
||||
#kolla_bifrost_inspector_rules:
|
||||
|
||||
###############################################################################
|
||||
# Inventory configuration.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user