Merge "Add action for generating fencing parameters."
This commit is contained in:
commit
5d977af0ac
@ -8,6 +8,8 @@ features:
|
||||
- Add a new Workflow which can be used to wait for Heat stacks finish with
|
||||
COMPLETE or FAILED.
|
||||
- CephMdsKey is now a generated Heat parameter.
|
||||
- Add an new Action which generates environment parameters for configuring
|
||||
fencing.
|
||||
fixes:
|
||||
- Fixes `bug 1644756 <https://bugs.launchpad.net/tripleo/+bug/1644756>`__ so
|
||||
that flavour matching works as expected with the object-storage role.
|
||||
|
@ -78,6 +78,7 @@ mistral.actions =
|
||||
tripleo.parameters.update_role = tripleo_common.actions.parameters:UpdateRoleParametersAction
|
||||
tripleo.parameters.generate_passwords = tripleo_common.actions.parameters:GeneratePasswordsAction
|
||||
tripleo.parameters.get_passwords = tripleo_common.actions.parameters:GetPasswordsAction
|
||||
tripleo.parameters.generate_fencing = tripleo_common.actions.parameters:GenerateFencingParametersAction
|
||||
tripleo.plan.create = tripleo_common.actions.plan:CreatePlanAction
|
||||
tripleo.plan.update = tripleo_common.actions.plan:UpdatePlanAction
|
||||
tripleo.plan.create_container = tripleo_common.actions.plan:CreateContainerAction
|
||||
|
@ -34,6 +34,7 @@ from mistral.workflow import utils as mistral_workflow_utils
|
||||
from tripleo_common.actions import base
|
||||
from tripleo_common.actions import templates
|
||||
from tripleo_common import constants
|
||||
from tripleo_common.utils import nodes
|
||||
from tripleo_common.utils import parameters
|
||||
from tripleo_common.utils import passwords as password_utils
|
||||
|
||||
@ -210,3 +211,87 @@ class GetPasswordsAction(base.TripleOAction):
|
||||
passwords[name] = parameter_defaults[name]
|
||||
|
||||
return passwords
|
||||
|
||||
|
||||
class GenerateFencingParametersAction(base.TripleOAction):
|
||||
"""Generates fencing configuration for a deployment.
|
||||
|
||||
:param nodes_json: list of nodes & attributes in json format
|
||||
:param os_auth: dictionary of OS client auth data (if using pxe_ssh)
|
||||
:param fence_action: action to take when fencing nodes
|
||||
:param delay: time to wait before taking fencing action
|
||||
:param ipmi_level: IPMI user level to use
|
||||
:param ipmi_cipher: IPMI cipher suite to use
|
||||
:param ipmi_lanplus: whether to use IPMIv2.0
|
||||
"""
|
||||
|
||||
def __init__(self, nodes_json, os_auth, fence_action, delay,
|
||||
ipmi_level, ipmi_cipher, ipmi_lanplus):
|
||||
super(GenerateFencingParametersAction, self).__init__()
|
||||
self.nodes_json = nodes_json
|
||||
self.os_auth = os_auth
|
||||
self.fence_action = fence_action
|
||||
self.delay = delay
|
||||
self.ipmi_level = ipmi_level
|
||||
self.ipmi_cipher = ipmi_cipher
|
||||
self.ipmi_lanplus = ipmi_lanplus
|
||||
|
||||
def run(self):
|
||||
"""Returns the parameters for fencing controller nodes"""
|
||||
hostmap = nodes.generate_hostmap(self.get_baremetal_client(),
|
||||
self.get_compute_client())
|
||||
fence_params = {"EnableFencing": True, "FencingConfig": {}}
|
||||
devices = []
|
||||
|
||||
for node in self.nodes_json:
|
||||
node_data = {}
|
||||
params = {}
|
||||
if "mac" in node:
|
||||
# Not all Ironic drivers present a MAC address, so we only
|
||||
# capture it if it's present
|
||||
mac_addr = node["mac"][0]
|
||||
node_data["host_mac"] = mac_addr
|
||||
|
||||
# Build up fencing parameters based on which Ironic driver this
|
||||
# node is using
|
||||
if node["pm_type"] == "pxe_ssh":
|
||||
# Ironic fencing driver
|
||||
node_data["agent"] = "fence_ironic"
|
||||
params["action"] = self.fence_action
|
||||
params["auth_url"] = self.os_auth["auth_url"]
|
||||
params["login"] = self.os_auth["login"]
|
||||
params["passwd"] = self.os_auth["passwd"]
|
||||
params["tenant_name"] = self.os_auth["tenant_name"]
|
||||
params["pcmk_host_map"] = "%(compute_name)s:%(bm_name)s" % (
|
||||
{"compute_name": hostmap[mac_addr]["compute_name"],
|
||||
"bm_name": hostmap[mac_addr]["baremetal_name"]})
|
||||
if self.delay:
|
||||
params["delay"] = self.delay
|
||||
elif node["pm_type"].split('_')[1] in ("ipmitool", "ilo", "drac"):
|
||||
# IPMI fencing driver
|
||||
node_data["agent"] = "fence_ipmilan"
|
||||
params["action"] = self.fence_action
|
||||
params["ipaddr"] = node["pm_addr"]
|
||||
params["passwd"] = node["pm_password"]
|
||||
params["login"] = node["pm_user"]
|
||||
params["pcmk_host_list"] = hostmap[mac_addr]["compute_name"]
|
||||
if "pm_port" in node:
|
||||
params["ipport"] = node["pm_port"]
|
||||
if self.ipmi_lanplus:
|
||||
params["lanplus"] = self.ipmi_lanplus
|
||||
if self.delay:
|
||||
params["delay"] = self.delay
|
||||
if self.ipmi_cipher:
|
||||
params["cipher"] = self.ipmi_cipher
|
||||
if self.ipmi_level:
|
||||
params["privlvl"] = self.ipmi_level
|
||||
else:
|
||||
error = ("Unable to generate fencing parameters for %s" %
|
||||
node["pm_type"])
|
||||
raise ValueError(error)
|
||||
|
||||
node_data["params"] = params
|
||||
devices.append(node_data)
|
||||
|
||||
fence_params["FencingConfig"]["devices"] = devices
|
||||
return {"parameter_defaults": fence_params}
|
||||
|
@ -497,3 +497,99 @@ class GetPasswordsActionTest(base.TestCase):
|
||||
|
||||
# ensure old passwords used and no new generation
|
||||
self.assertEqual(_EXISTING_PASSWORDS, result)
|
||||
|
||||
|
||||
class GenerateFencingParametersActionTestCase(base.TestCase):
|
||||
|
||||
@mock.patch('tripleo_common.utils.nodes.'
|
||||
'generate_hostmap')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_compute_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_baremetal_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_workflow_client')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
@mock.patch('mistral.context.ctx')
|
||||
def test_no_success(self, mock_ctx, mock_get_orchestration,
|
||||
mock_get_workflow, mock_get_baremetal,
|
||||
mock_get_compute, mock_generate_hostmap):
|
||||
test_hostmap = {
|
||||
"00:11:22:33:44:55": {
|
||||
"compute_name": "compute_name_0",
|
||||
"baremetal_name": "baremetal_name_0"
|
||||
},
|
||||
"11:22:33:44:55:66": {
|
||||
"compute_name": "compute_name_1",
|
||||
"baremetal_name": "baremetal_name_1"
|
||||
}
|
||||
}
|
||||
mock_generate_hostmap.return_value = test_hostmap
|
||||
|
||||
test_envjson = [{
|
||||
"name": "control-0",
|
||||
"pm_password": "control-0-password",
|
||||
"pm_type": "pxe_ipmitool",
|
||||
"pm_user": "control-0-admin",
|
||||
"pm_addr": "0.1.2.3",
|
||||
"pm_port": "0123",
|
||||
"mac": [
|
||||
"00:11:22:33:44:55"
|
||||
]
|
||||
}, {
|
||||
"name": "control-1",
|
||||
"pm_password": "control-1-password",
|
||||
"pm_type": "pxe_ssh",
|
||||
"pm_user": "control-1-admin",
|
||||
"pm_addr": "1.2.3.4",
|
||||
"mac": [
|
||||
"11:22:33:44:55:66"
|
||||
]
|
||||
}]
|
||||
test_osauth = {
|
||||
"auth_url": "test://auth.url",
|
||||
"login": "test_os_username",
|
||||
"passwd": "test_os_password",
|
||||
"tenant_name": "test_os_tenant_name",
|
||||
}
|
||||
|
||||
action = parameters.GenerateFencingParametersAction(test_envjson,
|
||||
test_osauth,
|
||||
"test_action",
|
||||
28,
|
||||
5,
|
||||
0,
|
||||
True)
|
||||
|
||||
result = action.run()["parameter_defaults"]
|
||||
|
||||
self.assertTrue(result["EnableFencing"])
|
||||
self.assertEqual(result["FencingConfig"]["devices"][0], {
|
||||
"agent": "fence_ipmilan",
|
||||
"host_mac": "00:11:22:33:44:55",
|
||||
"params": {
|
||||
"action": "test_action",
|
||||
"delay": 28,
|
||||
"ipaddr": "0.1.2.3",
|
||||
"ipport": "0123",
|
||||
"lanplus": True,
|
||||
"privlvl": 5,
|
||||
"login": "control-0-admin",
|
||||
"passwd": "control-0-password",
|
||||
"pcmk_host_list": "compute_name_0"
|
||||
}
|
||||
})
|
||||
self.assertEqual(result["FencingConfig"]["devices"][1], {
|
||||
"agent": "fence_ironic",
|
||||
"host_mac": "11:22:33:44:55:66",
|
||||
"params": {
|
||||
"auth_url": "test://auth.url",
|
||||
"delay": 28,
|
||||
"action": "test_action",
|
||||
"login": "test_os_username",
|
||||
"passwd": "test_os_password",
|
||||
"tenant_name": "test_os_tenant_name",
|
||||
"pcmk_host_map": "compute_name_1:baremetal_name_1"
|
||||
}
|
||||
})
|
||||
|
@ -432,3 +432,14 @@ def update_node_capability(node_uuid, capability, value, client):
|
||||
node = client.node.get(node_uuid)
|
||||
patch = _get_capability_patch(node, capability, value)
|
||||
return client.node.update(node_uuid, patch)
|
||||
|
||||
|
||||
def generate_hostmap(baremetal_client, compute_client):
|
||||
"""Create a map between Compute nodes and Baremetal nodes"""
|
||||
hostmap = {}
|
||||
for node in compute_client.servers.list():
|
||||
bm_node = baremetal_client.node.get_by_instance_uuid(node.id)
|
||||
for port in baremetal_client.port.list(node=bm_node.uuid):
|
||||
hostmap[port.address] = {"compute_name": node.name,
|
||||
"baremetal_name": bm_node.name}
|
||||
return hostmap
|
||||
|
Loading…
Reference in New Issue
Block a user