python-tripleoclient/tripleoclient/workflows/baremetal.py

582 lines
18 KiB
Python

# -*- coding: utf-8 -*-
# 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.
from __future__ import print_function
import six
from tripleoclient import exceptions
from tripleoclient.workflows import base
def validate_nodes(clients, **workflow_input):
"""Node Registration or Update
Run the tripleo.baremetal.v1.validate_nodes Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.validate_nodes',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if 'message' in payload:
print(payload['message'])
if payload['status'] == 'SUCCESS':
print('Successfully validated environment file')
return True
else:
raise exceptions.RegisterOrUpdateError(
'Exception validating environment file: {}'.format(
payload['message'])
)
def register_or_update(clients, **workflow_input):
"""Node Registration or Update
Run the tripleo.baremetal.v1.register_or_update Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.register_or_update',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if 'message' in payload:
print(payload['message'])
if payload['status'] == 'SUCCESS':
registered_nodes = payload['registered_nodes']
for nd in registered_nodes:
print('Successfully registered node UUID %s' % nd['uuid'])
return registered_nodes
else:
raise exceptions.RegisterOrUpdateError(
'Exception registering nodes: {}'.format(payload['message']))
def _format_errors(payload):
errors = []
messages = payload.get('message', [])
for msg in messages:
# Adapt for different formats
if isinstance(msg, six.string_types):
text = msg
else:
text = msg.get('result') or msg.get('message', '')
try:
# With multiple workflows, the error message can become
# quite large and unreadable as it gets passed from task to
# task. This attempts to keep only the last, and hopefully
# useful part.
errors.append(text.rstrip('\n').split('\n')[-1])
except Exception:
errors.append(text)
return '\n'.join(errors)
def provide(clients, **workflow_input):
"""Provide Baremetal Nodes
Run the tripleo.baremetal.v1.provide Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.provide',
workflow_input={'node_uuids': workflow_input['node_uuids']}
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if 'message' in payload:
print(payload['message'])
if payload['status'] != 'SUCCESS':
try:
message = _format_errors(payload)
except Exception:
message = 'Failed.'
raise exceptions.NodeProvideError(
'Failed to set nodes to available state: {}'.format(message))
def introspect(clients, **workflow_input):
"""Introspect Baremetal Nodes
Run the tripleo.baremetal.v1.introspect Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
print("Waiting for introspection to finish...")
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.introspect',
workflow_input={
'node_uuids': workflow_input['node_uuids'],
'run_validations': workflow_input['run_validations'],
'concurrency': workflow_input.get('concurrency', 20)
}
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if 'message' in payload:
print(payload['message'])
if payload['status'] != 'SUCCESS':
raise exceptions.IntrospectionError(
"Introspection completed with errors: {}"
.format(payload['message']))
def introspect_manageable_nodes(clients, **workflow_input):
"""Introspect all manageable nodes
Run the tripleo.baremetal.v1.introspect_manageable_nodes Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
print("Waiting for introspection to finish...")
errors = []
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.introspect_manageable_nodes',
workflow_input={
'run_validations': workflow_input['run_validations'],
'concurrency': workflow_input.get('concurrency', 20)
}
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if 'message' in payload:
print(payload['message'])
if payload['status'] == 'SUCCESS':
introspected_nodes = payload['introspected_nodes'] or {}
for node_uuid, status in introspected_nodes.items():
if status['error'] is not None:
errors.append("%s: %s" % (node_uuid, status['error']))
else:
raise exceptions.IntrospectionError(
'Exception introspecting nodes: {}'.format(payload['message']))
if errors:
raise exceptions.IntrospectionError(
"Introspection completed with errors:\n%s" % '\n'
.join(errors))
print("Introspection completed.")
def provide_manageable_nodes(clients, **workflow_input):
"""Provide all manageable Nodes
Run the tripleo.baremetal.v1.provide_manageable_nodes Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.provide_manageable_nodes',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if 'message' in payload:
print(payload['message'])
if payload['status'] != 'SUCCESS':
raise exceptions.NodeProvideError(
'Exception providing nodes:{}'.format(payload['message']))
print(payload['message'])
def configure(clients, **workflow_input):
"""Configure Node boot options.
Run the tripleo.baremetal.v1.configure Mistral workflow.
"""
workflow_client = clients.workflow_engine
ooo_client = clients.tripleoclient
with ooo_client.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.configure',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if 'message' in payload:
print(payload['message'])
if payload['status'] != 'SUCCESS':
raise exceptions.NodeConfigurationError(
'Failed to configure nodes: {}'.format(payload['message']))
def configure_manageable_nodes(clients, **workflow_input):
"""Configure all manageable Nodes.
Run the tripleo.baremetal.v1.configure_manageable_nodes Mistral workflow.
"""
workflow_client = clients.workflow_engine
ooo_client = clients.tripleoclient
with ooo_client.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.configure_manageable_nodes',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if 'message' in payload:
print(payload['message'])
if payload['status'] != 'SUCCESS':
raise exceptions.NodeConfigurationError(
'Exception configuring nodes: {}'.format(payload['message']))
print(payload['message'])
def create_raid_configuration(clients, **workflow_input):
"""Create RAID configuration on nodes.
Run the tripleo.baremetal.v1.create_raid_configuration Mistral workflow.
"""
workflow_client = clients.workflow_engine
ooo_client = clients.tripleoclient
print('Creating RAID configuration for given nodes, this may take time')
with ooo_client.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.create_raid_configuration',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if 'message' in payload:
print(payload['message'])
if payload['status'] == 'SUCCESS':
print('Success')
else:
raise RuntimeError(
'Failed to create RAID: {}'.format(payload['message']))
def discover_and_enroll(clients, **workflow_input):
"""Discover nodes.
Run the tripleo.baremetal.v1.discover_and_enroll_nodes Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.discover_and_enroll_nodes',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if payload.get('message'):
print(payload['message'])
if payload['status'] == 'SUCCESS':
registered_nodes = payload['registered_nodes']
for nd in registered_nodes:
print('Successfully registered node UUID %s' % nd['uuid'])
return registered_nodes
else:
raise exceptions.RegisterOrUpdateError(
'Exception discovering nodes: {}'.format(payload['message']))
def clean_nodes(clients, **workflow_input):
"""Clean Baremetal Nodes
Run the tripleo.baremetal.v1.clean_nodes Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.clean_nodes',
workflow_input={'node_uuids': workflow_input['node_uuids']}
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if payload.get('message'):
print(payload['message'])
if payload['status'] != 'SUCCESS':
message = _format_errors(payload)
raise exceptions.NodeConfigurationError(
'Error(s) cleaning nodes:\n{}'.format(message))
print('Successfully cleaned nodes')
def clean_manageable_nodes(clients, **workflow_input):
"""Clean all manageable Nodes
Run the tripleo.baremetal.v1.clean_manageable_nodes Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.clean_manageable_nodes',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if payload.get('message'):
print(payload['message'])
if payload['status'] != 'SUCCESS':
raise exceptions.NodeConfigurationError(
'Error cleaning nodes: {}'.format(payload['message']))
print('Cleaned %d node(s)' % len(payload['cleaned_nodes']))
def apply_bios_configuration(clients, **workflow_input):
"""Apply BIOS settings on nodes.
Run the tripleo.baremetal.v1.apply_bios_settings Mistral workflow.
"""
workflow_client = clients.workflow_engine
ooo_client = clients.tripleoclient
print('Applying BIOS settings for given nodes, this may take time')
with ooo_client.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.apply_bios_settings',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if payload.get('message'):
print(payload['message'])
if payload['status'] == 'SUCCESS':
print('Success')
else:
raise RuntimeError(
'Failed to apply BIOS settings: {}'.format(payload['message']))
def apply_bios_configuration_on_manageable_nodes(clients, **workflow_input):
"""Apply BIOS settings on manageable nodes.
Run the tripleo.baremetal.v1.apply_bios_settings_on_manageable_nodes
Mistral workflow.
"""
workflow_client = clients.workflow_engine
ooo_client = clients.tripleoclient
print('Applying BIOS settings for manageable nodes, this may take time')
with ooo_client.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.apply_bios_settings_on_manageable_nodes',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if payload.get('message'):
print(payload['message'])
if payload['status'] == 'SUCCESS':
print('Success')
else:
raise RuntimeError(
'Failed to apply BIOS settings: {}'.format(payload['message']))
def reset_bios_configuration(clients, **workflow_input):
"""Reset BIOS settings on nodes.
Run the tripleo.baremetal.v1.reset_bios_settings Mistral workflow.
"""
workflow_client = clients.workflow_engine
ooo_client = clients.tripleoclient
print('Reset BIOS settings on given nodes, this may take time')
with ooo_client.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.reset_bios_settings',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if payload.get('message'):
print(payload['message'])
if payload['status'] == 'SUCCESS':
print('Success')
else:
raise RuntimeError(
'Failed to reset BIOS settings: {}'.format(payload['message']))
def reset_bios_configuration_on_manageable_nodes(clients, **workflow_input):
"""Reset BIOS settings on manageable nodes.
Run the tripleo.baremetal.v1.reset_bios_settings_on_manageable_nodes
Mistral workflow.
"""
workflow_client = clients.workflow_engine
ooo_client = clients.tripleoclient
print('Reset BIOS settings on manageable nodes, this may take time')
with ooo_client.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal.v1.reset_bios_settings_on_manageable_nodes',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if payload.get('message'):
print(payload['message'])
if payload['status'] == 'SUCCESS':
print('Success')
else:
raise RuntimeError(
'Failed to reset BIOS settings: {}'.format(payload['message']))
def deploy_roles(clients, **workflow_input):
"""Deploy provided roles using Ironic.
Run the tripleo.baremetal_deploy.v1.deploy_roles Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal_deploy.v1.deploy_roles',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if payload.get('message'):
print(payload['message'])
if payload['status'] != 'SUCCESS':
raise exceptions.NodeConfigurationError(
'Error deploying nodes: {}'.format(payload['message']))
return payload
def undeploy_roles(clients, **workflow_input):
"""Undeploy provided roles using Ironic.
Run the tripleo.baremetal_deploy.v1.undeploy_roles Mistral workflow.
"""
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient
with tripleoclients.messaging_websocket() as ws:
execution = base.start_workflow(
workflow_client,
'tripleo.baremetal_deploy.v1.undeploy_roles',
workflow_input=workflow_input
)
for payload in base.wait_for_messages(workflow_client, ws, execution):
if payload.get('message'):
print(payload['message'])
if payload['status'] != 'SUCCESS':
raise exceptions.NodeConfigurationError(
'Error undeploying nodes: {}'.format(payload['message']))
return payload
def expand_roles(clients, roles, stackname, provisioned):
workflow_client = clients.workflow_engine
return base.call_action(
workflow_client,
'tripleo.baremetal_deploy.expand_roles',
roles=roles,
stackname=stackname,
provisioned=provisioned
)