Add support for redis sentinel and slaves

If the correct configuration settings are set in the answer file
redis and redis-sentinel will be installed and configured on slave
and sentinel hosts. The sentinels will monitor the master and
keep track of the slaves. If the master dies, then the sentinels
will consensually establish a new master.

Change-Id: I7acc5e4f7bb99692bfe1c8694e8ddb0c472160f4
This commit is contained in:
Chris Dent 2015-01-05 23:38:16 +00:00
parent 38bcdb2491
commit 3fd2f89875
6 changed files with 215 additions and 25 deletions

View File

@ -444,11 +444,36 @@ Ceilometer Config Parameters
Specify an optional backend for group membership coordination in the alarm evaluator and central
agent. Currently the only valid option are 'redis' or 'none'. The default is 'redis'.
**CONFIG_REDIS_HOST**
**CONFIG_REDIS_MASTER_HOST**
The IP address of the server on which to install Redis, if Redis is being used for coordination.
**CONFIG_REDIS_PORT**
The port on which the Redis server will listen, if Redis is being used for coordination.
The port on which all Redis servers will listen, if Redis is being used for coordination.
**CONFIG_REDIS_HA**
Whether redis-sentinel and redis-slaves should be used to to enable high availability in Redis
coordination. Valid options are 'y' or 'n'. Default is 'n'. The following settings only apply if
'y' is chosen.
**CONFIG_REDIS_SLAVE_HOSTS**
A comma-separated list of hosts that will operate as Redis slaves and on which Redis will be
installed.
**CONFIG_REDIS_SENTINEL_HOSTS**
A comma-separated list of hosts that will operate as Redis sentinels and on which Redis will be
installed.
**CONFIG_REDIS_SENTINEL_CONTACT_HOST**
One of the sentinel hosts which will be used to configure coordination.
**CONFIG_REDIS_SENTINEL_PORT**
The port on which all Redis sentinels will listen. Defaults to 26379.
**CONFIG_REDIS_SENTINEL_QUORUM**
The quorum value for the Redis sentinels. Default value is 2, but you should change this.
**CONFIG_REDIS_MASTER_NAME**
The logical name of the initial Redis master, required in sentinel and client configuration.
Heat Config Parameters
----------------------

View File

@ -9,6 +9,7 @@ import uuid
from packstack.installer import utils
from packstack.installer import validators
from packstack.installer import processors
from packstack.installer.utils import split_hosts
from packstack.modules.shortcuts import get_mq
from packstack.modules.ospluginutils import (getManifestTemplate,
appendManifestFile,
@ -81,31 +82,120 @@ def initConfig(controller):
"CONDITION": False},
],
"REDIS": [
{"CMD_OPTION": "redis-host",
{"CMD_OPTION": "redis-master-host",
"USAGE": ("The IP address of the server on which to install "
"redis"),
"PROMPT": "Enter the IP address of the redis server",
"redis master server"),
"PROMPT": "Enter the IP address of the redis master server",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_ssh],
"DEFAULT_VALUE": utils.get_localhost_ip(),
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_REDIS_HOST",
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_MASTER_HOST",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
"CONDITION": False,
"DEPRECATES": ["CONFIG_REDIS_HOST"]},
{"CMD_OPTION": "redis-port",
"USAGE": "The port on which the redis server listens",
"PROMPT": "Enter the port of the redis server",
"USAGE": "The port on which the redis server(s) listens",
"PROMPT": "Enter the port of the redis server(s)",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_port],
"DEFAULT_VALUE": 6379,
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_PORT",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "redis-ha",
"USAGE": "Should redis try to use HA",
"PROMPT": "Should redis try to use HA?",
"OPTION_LIST": ["y", "n"],
"VALIDATORS": [validators.validate_options],
"DEFAULT_VALUE": "n",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_HA",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "redis-slaves",
"USAGE": "The hosts on which to install redis slaves",
"PROMPT": "Enter the IP addresses of the redis slave servers",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_multi_ssh],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_SLAVE_HOSTS",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "redis-sentinels",
"USAGE": "The hosts on which to install redis sentinel servers",
"PROMPT": "Enter the IP addresses of the redis sentinel servers",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_multi_ssh],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_SENTINEL_HOSTS",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "redis-sentinel-contact",
"USAGE": "The host to configure as the coordination sentinel",
"PROMPT":
"Enter the IP address of the coordination redis sentinel",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_ssh],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_SENTINEL_CONTACT_HOST",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "redis-sentinel-port",
"USAGE": "The port on which redis sentinel servers listen",
"PROMPT": ("Enter the port on which the redis sentinel servers"
" listen"),
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_port],
"DEFAULT_VALUE": 26379,
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_SENTINEL_PORT",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "redis-sentinel-quorum",
"USAGE": "The quorum value for redis sentinel servers",
"PROMPT": (
"Enter the quorum value for the redis sentinel servers"),
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_integer],
"DEFAULT_VALUE": 2,
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_SENTINEL_QUORUM",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "redis-sentinel-master-name",
"USAGE": "The name of the master server watched by the sentinel",
"PROMPT": (
"Enter the logical name of the master server"),
"OPTION_LIST": [r'[a-z]+'],
"VALIDATORS": [validators.validate_regexp],
"DEFAULT_VALUE": 'mymaster',
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_MASTER_NAME",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
],
}
@ -197,24 +287,70 @@ def create_mongodb_manifest(config, messages):
def create_redis_manifest(config, messages):
if config['CONFIG_CEILOMETER_COORDINATION_BACKEND'] == 'redis':
manifestfile = "%s_redis.pp" % config['CONFIG_REDIS_HOST']
# master
manifestfile = "%s_redis.pp" % config['CONFIG_REDIS_MASTER_HOST']
manifestdata = getManifestTemplate("redis.pp")
fw_details = dict()
key = "redis_server"
fw_details.setdefault(key, {})
fw_details[key]['host'] = "%s" % config['CONFIG_CONTROLLER_HOST']
fw_details[key]['service_name'] = "redis-server"
fw_details[key]['chain'] = "INPUT"
fw_details[key]['ports'] = config['CONFIG_REDIS_PORT']
fw_details[key]['proto'] = "tcp"
config['FIREWALL_REDIS_RULES'] = fw_details
master_clients = set([config['CONFIG_CONTROLLER_HOST']]).union(
split_hosts(config['CONFIG_REDIS_SLAVE_HOSTS'])).union(
split_hosts(config['CONFIG_REDIS_SENTINEL_HOSTS']))
config['FIREWALL_REDIS_RULES'] = _create_redis_firewall_rules(
master_clients, config['CONFIG_REDIS_PORT'])
manifestdata += createFirewallResources('FIREWALL_REDIS_RULES')
appendManifestFile(manifestfile, manifestdata, 'pre')
# slaves
if config['CONFIG_REDIS_HA'] == 'y':
for slave in split_hosts(config['CONFIG_REDIS_SLAVE_HOSTS']):
config['CONFIG_REDIS_HOST'] = slave
manifestfile = "%s_redis_slave.pp" % slave
manifestdata = getManifestTemplate("redis_slave.pp")
slave_clients = set([config['CONFIG_CONTROLLER_HOST']]).union(
split_hosts(config['CONFIG_REDIS_SLAVE_HOSTS'])).union(
split_hosts(config['CONFIG_REDIS_SENTINEL_HOSTS']))
config['FIREWALL_REDIS_SLAVE_RULES'] = (
_create_redis_firewall_rules(
slave_clients, config['CONFIG_REDIS_PORT']))
manifestdata += createFirewallResources(
'FIREWALL_REDIS_SLAVE_RULES')
appendManifestFile(manifestfile, manifestdata, 'pre')
# sentinels
if config['CONFIG_REDIS_HA'] == 'y':
for sentinel in split_hosts(config['CONFIG_REDIS_SENTINEL_HOSTS']):
manifestfile = "%s_redis_sentinel.pp" % sentinel
manifestdata = getManifestTemplate("redis_sentinel.pp")
config['FIREWALL_SENTINEL_RULES'] = (
_create_redis_firewall_rules(
split_hosts(config['CONFIG_REDIS_SENTINEL_HOSTS']),
config['CONFIG_REDIS_SENTINEL_PORT']))
manifestdata += createFirewallResources(
'FIREWALL_SENTINEL_RULES')
appendManifestFile(manifestfile, manifestdata, 'pre')
def create_keystone_manifest(config, messages):
manifestfile = "%s_keystone.pp" % config['CONFIG_CONTROLLER_HOST']
manifestdata = getManifestTemplate("keystone_ceilometer")
appendManifestFile(manifestfile, manifestdata)
# ------------------------- helper functions -------------------------
def _create_redis_firewall_rules(hosts, port):
fw_details = dict()
for host in hosts:
key = "redis service from %s" % host
fw_details.setdefault(key, {})
fw_details[key]['host'] = "%s" % host
fw_details[key]['service_name'] = "redis service"
fw_details[key]['chain'] = "INPUT"
fw_details[key]['ports'] = port
fw_details[key]['proto'] = "tcp"
return fw_details

View File

@ -3,9 +3,16 @@ $config_mongodb_host = hiera('CONFIG_MONGODB_HOST')
$config_ceilometer_coordination_backend = hiera('CONFIG_CEILOMETER_COORDINATION_BACKEND')
if $config_ceilometer_coordination_backend == 'redis' {
$redis_host = hiera('CONFIG_REDIS_HOST')
$redis_host = hiera('CONFIG_REDIS_MASTER_HOST')
$redis_port = hiera('CONFIG_REDIS_PORT')
$coordination_url = "redis://${redis_host}:${redis_port}"
$sentinel_host = hiera('CONFIG_REDIS_SENTINEL_CONTACT_HOST')
if $sentinel_host != '' {
$master_name = hiera('CONFIG_REDIS_MASTER_NAME')
$sentinel_port = hiera('CONFIG_REDIS_SENTINEL_PORT')
$coordination_url = "redis://${sentinel_host}:${sentinel_port}?sentinel=${master_name}"
} else {
$coordination_url = "redis://${redis_host}:${redis_port}"
}
} else {
$coordination_url = ''
}

View File

@ -1,8 +1,8 @@
$redis_host = hiera('CONFIG_REDIS_HOST')
$redis_port = hiera('CONFIG_REDIS_PORT')
$redis_master_host = hiera('CONFIG_REDIS_MASTER_HOST')
class { 'redis':
bind => $redis_host,
bind => $redis_master_host,
port => $redis_port,
appendonly => true,
daemonize => false,

View File

@ -0,0 +1,11 @@
$redis_master_host = hiera('CONFIG_REDIS_MASTER_HOST')
$redis_master_port = hiera('CONFIG_REDIS_PORT')
$redis_master_name = hiera('CONFIG_REDIS_MASTER_NAME')
$redis_sentinel_quorum = hiera('CONFIG_REDIS_SENTINEL_QUORUM')
class { 'redis::sentinel':
master_name => "${redis_master_name}",
redis_host => $redis_master_host,
redis_port => $redis_master_port,
quorum => $redis_sentinel_quorum,
}

View File

@ -0,0 +1,11 @@
$redis_host = hiera('CONFIG_REDIS_HOST')
$redis_port = hiera('CONFIG_REDIS_PORT')
$redis_master_host = hiera('CONFIG_REDIS_MASTER_HOST')
class { 'redis':
bind => $redis_host,
port => $redis_port,
appendonly => true,
daemonize => false,
slaveof => "${redis_master_host} ${redis_port}",
}