packstack/packstack/plugins/ceilometer_800.py

428 lines
17 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.
"""
Installs and configures Ceilometer
"""
import uuid
from packstack.installer import basedefs
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.documentation import update_params_usage
from packstack.modules.shortcuts import get_mq
from packstack.modules.ospluginutils import appendManifestFile
from packstack.modules.ospluginutils import createFirewallResources
from packstack.modules.ospluginutils import getManifestTemplate
from packstack.modules.ospluginutils import generate_ssl_cert
# ------------- Ceilometer Packstack Plugin Initialization --------------
PLUGIN_NAME = "OS-Ceilometer"
PLUGIN_NAME_COLORED = utils.color_text(PLUGIN_NAME, 'blue')
def initConfig(controller):
ceilometer_params = {
"CEILOMETER": [
{"CONF_NAME": "CONFIG_CEILOMETER_SECRET",
"CMD_OPTION": "ceilometer-secret",
"PROMPT": "Enter the Ceilometer secret key",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_not_empty],
"DEFAULT_VALUE": uuid.uuid4().hex[:16],
"MASK_INPUT": True,
"LOOSE_VALIDATION": False,
"USE_DEFAULT": True,
"NEED_CONFIRM": True,
"CONDITION": False},
{"CONF_NAME": "CONFIG_CEILOMETER_KS_PW",
"CMD_OPTION": "ceilometer-ks-passwd",
"PROMPT": "Enter the password for the Ceilometer Keystone access",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_not_empty],
"DEFAULT_VALUE": "PW_PLACEHOLDER",
"PROCESSORS": [processors.process_password],
"MASK_INPUT": True,
"LOOSE_VALIDATION": False,
"USE_DEFAULT": False,
"NEED_CONFIRM": True,
"CONDITION": False},
{"CMD_OPTION": "ceilometer-service-name",
"PROMPT": "Enter the Ceilometer service name.",
"OPTION_LIST": ['ceilometer', 'httpd'],
"VALIDATORS": [validators.validate_options],
"DEFAULT_VALUE": "httpd",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": 'CONFIG_CEILOMETER_SERVICE_NAME',
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CONF_NAME": "CONFIG_CEILOMETER_COORDINATION_BACKEND",
"CMD_OPTION": "ceilometer-coordination-backend",
"PROMPT": "Enter the coordination driver",
"OPTION_LIST": ['redis', 'none'],
"VALIDATORS": [validators.validate_options],
"DEFAULT_VALUE": 'redis',
"MASK_INPUT": False,
"USE_DEFAULT": True,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CONF_NAME": "CONFIG_CEILOMETER_METERING_BACKEND",
"CMD_OPTION": "ceilometer-metering-backend",
"PROMPT": "Enter the metering backend to use",
"OPTION_LIST": ['database', 'gnocchi'],
"VALIDATORS": [validators.validate_options],
"DEFAULT_VALUE": 'database',
"MASK_INPUT": False,
"USE_DEFAULT": True,
"NEED_CONFIRM": False,
"CONDITION": False},
],
"MONGODB": [
{"CMD_OPTION": "mongodb-host",
"PROMPT": "Enter the host for the MongoDB server",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_ssh],
"DEFAULT_VALUE": utils.get_localhost_ip(),
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_MONGODB_HOST",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
],
"REDIS": [
{"CMD_OPTION": "redis-master-host",
"PROMPT": "Enter the host for the Redis master server",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_ssh],
"DEFAULT_VALUE": utils.get_localhost_ip(),
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_MASTER_HOST",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False,
"DEPRECATES": ["CONFIG_REDIS_HOST"]},
{"CMD_OPTION": "redis-port",
"PROMPT": "Enter the port of the redis server(s)",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_port],
"DEFAULT_VALUE": 6379,
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_REDIS_PORT",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "redis-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",
"PROMPT": "Enter the host for 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",
"PROMPT": "Enter the host for 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",
"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",
"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",
"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",
"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},
],
}
update_params_usage(basedefs.PACKSTACK_DOC, ceilometer_params)
ceilometer_groups = [
{"GROUP_NAME": "CEILOMETER",
"DESCRIPTION": "Ceilometer Config parameters",
"PRE_CONDITION": "CONFIG_CEILOMETER_INSTALL",
"PRE_CONDITION_MATCH": "y",
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
{"GROUP_NAME": "MONGODB",
"DESCRIPTION": "MONGODB Config parameters",
"PRE_CONDITION": "CONFIG_CEILOMETER_INSTALL",
"PRE_CONDITION_MATCH": "y",
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
{"GROUP_NAME": "REDIS",
"DESCRIPTION": "Redis Config parameters",
"PRE_CONDITION": "CONFIG_CEILOMETER_COORDINATION_BACKEND",
"PRE_CONDITION_MATCH": "redis",
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
]
for group in ceilometer_groups:
paramList = ceilometer_params[group["GROUP_NAME"]]
controller.addGroup(group, paramList)
def initSequences(controller):
if controller.CONF['CONFIG_CEILOMETER_INSTALL'] != 'y':
return
steps = [{'title': 'Adding MongoDB manifest entries',
'functions': [create_mongodb_manifest]},
{'title': 'Adding Redis manifest entries',
'functions': [create_redis_manifest]},
{'title': 'Adding Ceilometer manifest entries',
'functions': [create_manifest]},
{'title': 'Adding Ceilometer Keystone manifest entries',
'functions': [create_keystone_manifest]}]
controller.addSequence("Installing OpenStack Ceilometer", [], [],
steps)
# -------------------------- step functions --------------------------
def create_manifest(config, messages):
manifestfile = "%s_ceilometer.pp" % config['CONFIG_CONTROLLER_HOST']
manifestdata = getManifestTemplate(get_mq(config, "ceilometer"))
manifestdata += getManifestTemplate("ceilometer")
if config['CONFIG_CEILOMETER_COORDINATION_BACKEND'] == 'redis':
# Determine if we need to configure multiple sentinel hosts as
# fallbacks for use in coordination url.
sentinel_hosts = split_hosts(config['CONFIG_REDIS_SENTINEL_HOSTS'])
sentinel_port = config['CONFIG_REDIS_SENTINEL_PORT']
sentinel_host = config['CONFIG_REDIS_SENTINEL_CONTACT_HOST']
if config['CONFIG_IP_VERSION'] == 'ipv6':
config['CONFIG_REDIS_SENTINEL_CONTACT_HOST_URL'] = "[%s]" % (
sentinel_host)
else:
config['CONFIG_REDIS_SENTINEL_CONTACT_HOST_URL'] = sentinel_host
sentinel_contact = config['CONFIG_REDIS_SENTINEL_CONTACT_HOST']
if len(sentinel_hosts) > 1:
sentinel_format = 'sentinel_fallback=%s:%s'
if config['CONFIG_IP_VERSION'] == 'ipv6':
sentinel_format = 'sentinel_fallback=[%s]:%s'
sentinel_fallbacks = '&'.join([sentinel_format %
(host, sentinel_port)
for host in sentinel_hosts
if host != sentinel_contact])
else:
sentinel_fallbacks = ''
config['CONFIG_REDIS_SENTINEL_FALLBACKS'] = sentinel_fallbacks
if config['CONFIG_AMQP_ENABLE_SSL'] == 'y':
ssl_cert_file = config['CONFIG_CEILOMETER_SSL_CERT'] = (
'/etc/pki/tls/certs/ssl_amqp_ceilometer.crt'
)
ssl_key_file = config['CONFIG_CEILOMETER_SSL_KEY'] = (
'/etc/pki/tls/private/ssl_amqp_ceilometer.key'
)
ssl_host = config['CONFIG_CONTROLLER_HOST']
service = 'ceilometer'
generate_ssl_cert(config, ssl_host, service, ssl_key_file,
ssl_cert_file)
fw_details = dict()
key = "ceilometer_api"
fw_details.setdefault(key, {})
fw_details[key]['host'] = "ALL"
fw_details[key]['service_name'] = "ceilometer-api"
fw_details[key]['chain'] = "INPUT"
fw_details[key]['ports'] = ['8777']
fw_details[key]['proto'] = "tcp"
config['FIREWALL_CEILOMETER_RULES'] = fw_details
manifestdata += createFirewallResources('FIREWALL_CEILOMETER_RULES')
# Add a template that creates a group for nova because the ceilometer
# class needs it
if config['CONFIG_NOVA_INSTALL'] == 'n':
manifestdata += getManifestTemplate("ceilometer_nova_disabled")
appendManifestFile(manifestfile, manifestdata, 'ceilometer')
def create_mongodb_manifest(config, messages):
host = config['CONFIG_MONGODB_HOST']
if config['CONFIG_IP_VERSION'] == 'ipv6':
config['CONFIG_MONGODB_HOST_URL'] = "[%s]" % host
else:
config['CONFIG_MONGODB_HOST_URL'] = host
manifestfile = "%s_mongodb.pp" % config['CONFIG_MONGODB_HOST']
manifestdata = getManifestTemplate("mongodb")
fw_details = dict()
key = "mongodb_server"
fw_details.setdefault(key, {})
fw_details[key]['host'] = "%s" % config['CONFIG_CONTROLLER_HOST']
fw_details[key]['service_name'] = "mongodb-server"
fw_details[key]['chain'] = "INPUT"
fw_details[key]['ports'] = ['27017']
fw_details[key]['proto'] = "tcp"
config['FIREWALL_MONGODB_RULES'] = fw_details
manifestdata += createFirewallResources('FIREWALL_MONGODB_RULES')
appendManifestFile(manifestfile, manifestdata, 'pre')
def create_redis_manifest(config, messages):
if config['CONFIG_CEILOMETER_COORDINATION_BACKEND'] == 'redis':
redis_master_host = config['CONFIG_REDIS_MASTER_HOST']
if config['CONFIG_IP_VERSION'] == 'ipv6':
config['CONFIG_REDIS_MASTER_HOST_URL'] = "[%s]" % redis_master_host
else:
config['CONFIG_REDIS_MASTER_HOST_URL'] = redis_master_host
# master
manifestfile = "%s_redis.pp" % config['CONFIG_REDIS_MASTER_HOST']
manifestdata = getManifestTemplate("redis.pp")
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