Merge "Add pacemaker authkey"

This commit is contained in:
Zuul 2019-04-03 14:15:47 +00:00 committed by Gerrit Code Review
commit 30ccef8c92
3 changed files with 159 additions and 0 deletions

View File

@ -53,6 +53,18 @@ options:
.
This configuration element is mandatory and the service will fail on
install if it is not provided. The value must be base64 encoded.
pacemaker_key:
type: string
default:
description: |
This value will become the Pacemaker authentication key. To generate
a suitable value use:
.
dd if=/dev/urandom of=/tmp/authkey bs=2048 count=1
cat /tmp/authkey | base64 -w 0
.
If this configuration element is not set then the corosync key will be
reused as the pacemaker key.
maintenance-mode:
type: boolean
default: false

View File

@ -93,6 +93,8 @@ COROSYNC_CONF_FILES = [
COROSYNC_HACLUSTER_ACL,
]
SUPPORTED_TRANSPORTS = ['udp', 'udpu', 'multicast', 'unicast']
PCMKR_AUTHKEY = '/etc/pacemaker/authkey'
PCMKR_MAX_RETRIES = 3
PCMKR_SLEEP_SECS = 5
@ -331,6 +333,11 @@ def emit_corosync_conf():
return False
def get_pcmkr_key():
"""Return the pacemaker auth key"""
return config('pacemaker_key') or config('corosync_key')
def emit_base_conf():
if not os.path.isdir(COROSYNC_HACLUSTER_ACL_DIR):
os.mkdir(COROSYNC_HACLUSTER_ACL_DIR)
@ -347,6 +354,12 @@ def emit_base_conf():
write_file(path=COROSYNC_AUTHKEY,
content=b64decode(corosync_key),
perms=0o400)
pcmkr_key = get_pcmkr_key()
write_file(path=PCMKR_AUTHKEY,
owner='root',
group='haclient',
content=b64decode(pcmkr_key),
perms=0o440)
return True
return False

View File

@ -442,3 +442,137 @@ class UtilsTestCase(unittest.TestCase):
relation_get.assert_has_calls([
mock.call('json_testkey', 'neutron-api/0', 'hacluster:1'),
])
@mock.patch.object(utils, 'render_template')
@mock.patch.object(utils.os.path, 'isdir')
@mock.patch.object(utils.os, 'mkdir')
@mock.patch.object(utils, 'write_file')
@mock.patch.object(utils, 'config')
def test_emit_base_conf(self, config, write_file, mkdir, isdir,
render_template):
cfg = {
'corosync_key': 'Y29yb3N5bmNrZXkK',
'pacemaker_key': 'cGFjZW1ha2Vya2V5Cg==',
}
config.side_effect = lambda x: cfg.get(x)
isdir.return_value = False
render = {
'corosync': 'corosync etc default config',
'hacluster.acl': 'hacluster acl file',
}
render_template.side_effect = lambda x, y: render[x]
expect_write_calls = [
mock.call(
content='corosync etc default config',
path='/etc/default/corosync'),
mock.call(
content='hacluster acl file',
path='/etc/corosync/uidgid.d/hacluster'),
mock.call(
content=b'corosynckey\n',
path='/etc/corosync/authkey',
perms=256),
mock.call(
content=b'pacemakerkey\n',
path='/etc/pacemaker/authkey',
perms=288,
group='haclient',
owner='root')
]
expect_render_calls = [
mock.call(
'corosync',
{'corosync_enabled': 'yes'}),
mock.call(
'hacluster.acl',
{})
]
self.assertTrue(utils.emit_base_conf())
write_file.assert_has_calls(expect_write_calls)
render_template.assert_has_calls(expect_render_calls)
mkdir.assert_called_once_with('/etc/corosync/uidgid.d')
@mock.patch.object(utils, 'render_template')
@mock.patch.object(utils.os.path, 'isdir')
@mock.patch.object(utils.os, 'mkdir')
@mock.patch.object(utils, 'write_file')
@mock.patch.object(utils, 'config')
def test_emit_base_conf_no_pcmkr_key(self, config, write_file, mkdir,
isdir, render_template):
cfg = {
'corosync_key': 'Y29yb3N5bmNrZXkK',
}
config.side_effect = lambda x: cfg.get(x)
isdir.return_value = False
render = {
'corosync': 'corosync etc default config',
'hacluster.acl': 'hacluster acl file',
}
render_template.side_effect = lambda x, y: render[x]
expect_write_calls = [
mock.call(
content='corosync etc default config',
path='/etc/default/corosync'),
mock.call(
content='hacluster acl file',
path='/etc/corosync/uidgid.d/hacluster'),
mock.call(
content=b'corosynckey\n',
path='/etc/corosync/authkey',
perms=256),
mock.call(
content=b'corosynckey\n',
path='/etc/pacemaker/authkey',
perms=288,
group='haclient',
owner='root')
]
expect_render_calls = [
mock.call(
'corosync',
{'corosync_enabled': 'yes'}),
mock.call(
'hacluster.acl',
{})
]
self.assertTrue(utils.emit_base_conf())
write_file.assert_has_calls(expect_write_calls)
render_template.assert_has_calls(expect_render_calls)
mkdir.assert_called_once_with('/etc/corosync/uidgid.d')
@mock.patch.object(utils, 'render_template')
@mock.patch.object(utils.os.path, 'isdir')
@mock.patch.object(utils.os, 'mkdir')
@mock.patch.object(utils, 'write_file')
@mock.patch.object(utils, 'config')
def test_emit_base_conf_no_coro_key(self, config, write_file, mkdir,
isdir, render_template):
cfg = {
}
config.side_effect = lambda x: cfg.get(x)
isdir.return_value = False
render = {
'corosync': 'corosync etc default config',
'hacluster.acl': 'hacluster acl file',
}
render_template.side_effect = lambda x, y: render[x]
expect_write_calls = [
mock.call(
content='corosync etc default config',
path='/etc/default/corosync'),
mock.call(
content='hacluster acl file',
path='/etc/corosync/uidgid.d/hacluster'),
]
expect_render_calls = [
mock.call(
'corosync',
{'corosync_enabled': 'yes'}),
mock.call(
'hacluster.acl',
{})
]
self.assertFalse(utils.emit_base_conf())
write_file.assert_has_calls(expect_write_calls)
render_template.assert_has_calls(expect_render_calls)
mkdir.assert_called_once_with('/etc/corosync/uidgid.d')