Clean-up resources dealing with notifications

This change refactors the lma_collector Puppet module regarding the
processing of the OpenStack notifications to get rid of the coupling with
Fuel. In particular, the configuration of the OpenStack services is
done in the external manifests since there was no point to have it in
lma_collector.

The change removes also workarounds that were necessary with older
versions of the plugin:

  - heat-engine is now managed as a regular service.
  - the can_exit flag is reverted back to false for the AMQP plugins

Finally it restarts properly the Keystone service if necessary:
Keystone is executed as a WSGI application in Apache so we need to
restart Apache if the Keystone configuration changes.

Change-Id: I39a2d25695449271b946ddcbca00cd8911dbdbb4
Implements: blueprint lma-without-fuel
This commit is contained in:
Simon Pasquier 2016-02-03 11:41:03 +01:00
parent 0660db02a8
commit 3f0cdd5061
11 changed files with 329 additions and 345 deletions

View File

@ -39,13 +39,27 @@ if $lma_collector['elasticsearch_mode'] != 'disabled' {
}
if $ceilometer['enabled'] {
$notification_topics = [$lma_collector::params::openstack_topic, $lma_collector::params::lma_topic]
$notification_topics = ['notifications', 'lma_notifications']
}
else {
$notification_topics = [$lma_collector::params::lma_topic]
$notification_topics = ['lma_notifications']
}
# OpenStack notifcations are always useful for indexation and metrics collection
class { 'lma_collector::notifications::cinder':
topics => $notification_topics,
include cinder::params
$volume_service = $::cinder::params::volume_service
cinder_config { 'DEFAULT/notification_topics':
value => join($notification_topics, ','),
notify => Service[$volume_service],
}
cinder_config { 'DEFAULT/notification_driver':
value => $driver,
notify => Service[$volume_service],
}
service { $volume_service:
hasstatus => true,
hasrestart => true,
}

View File

@ -41,15 +41,32 @@ if $lma_collector['influxdb_mode'] != 'disabled' {
}
if $ceilometer['enabled'] {
$notification_topics = [$lma_collector::params::openstack_topic, $lma_collector::params::lma_topic]
$notification_topics = ['notifications', 'lma_notifications']
}
else {
$notification_topics = [$lma_collector::params::lma_topic]
$notification_topics = ['lma_notifications']
}
# OpenStack notifcations are always useful for indexation and metrics collection
class { 'lma_collector::notifications::compute':
topics => $notification_topics,
include nova::params
$compute_service = $::nova::params::compute_service_name
nova_config { 'DEFAULT/notification_topics':
value => join($notification_topics, ','),
notify => Service[$compute_service],
}
nova_config { 'DEFAULT/notification_driver':
value => 'messaging',
notify => Service[$compute_service],
}
nova_config { 'DEFAULT/notify_on_state_change':
value => 'vm_and_task_state',
notify => Service[$compute_service],
}
service { $compute_service:
hasstatus => true,
hasrestart => true,
}
class { 'lma_collector::collectd::base':

View File

@ -27,10 +27,10 @@ $storage_options = hiera_hash('storage', {})
$murano = hiera_hash('murano')
if $ceilometer['enabled'] {
$notification_topics = [$lma_collector::params::openstack_topic, $lma_collector::params::lma_topic]
$notification_topics = ['notifications', 'lma_notifications']
}
else {
$notification_topics = [$lma_collector::params::lma_topic]
$notification_topics = ['lma_notifications']
}
if $rabbit['user'] {
@ -47,12 +47,153 @@ Service<| title == $lma_collector::params::service_name |> {
}
# OpenStack notifications are always useful for indexation and metrics collection
class { 'lma_collector::notifications::controller':
class { 'lma_collector::notifications::input':
topic => 'lma_notifications',
host => $messaging_address,
port => hiera('amqp_port', '5673'),
user => $rabbitmq_user,
password => $rabbit['password'],
topics => $notification_topics,
}
# Nova notifications
include nova::params
$nova_api_service = $::nova::params::api_service_name
$nova_conductor_service = $::nova::params::conductor_service_name
$nova_scheduler_service = $::nova::params::scheduler_service_name
nova_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$nova_api_service, $nova_conductor_service, $nova_scheduler_service],
}
nova_config { 'DEFAULT/notification_driver':
value => 'messaging',
notify => Service[$nova_api_service, $nova_conductor_service, $nova_scheduler_service],
}
nova_config { 'DEFAULT/notify_on_state_change':
value => 'vm_and_task_state',
notify => Service[$nova_api_service, $nova_conductor_service, $nova_scheduler_service],
}
service { [$nova_api_service, $nova_conductor_service, $nova_scheduler_service]:
hasstatus => true,
hasrestart => true,
}
# Cinder notifications
include cinder::params
$cinder_api_service = $::cinder::params::api_service
$cinder_scheduler_service = $::cinder::params::scheduler_service
cinder_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$cinder_api_service, $cinder_scheduler_service],
}
cinder_config { 'DEFAULT/notification_driver':
value => 'messaging',
notify => Service[$cinder_api_service, $cinder_scheduler_service],
}
service { [$cinder_api_service, $cinder_scheduler_service]:
hasstatus => true,
hasrestart => true,
}
# Keystone notifications
# Keystone is executed as a WSGI application inside Apache so the Apache
# service needs to be restarted if necessary
include apache::params
include apache::service
keystone_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Class['apache::service'],
}
keystone_config { 'DEFAULT/notification_driver':
value => 'messaging',
notify => Class['apache::service'],
}
# Neutron notifications
include neutron::params
neutron_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$::neutron::params::server_service],
}
neutron_config { 'DEFAULT/notification_driver':
value => 'messaging',
notify => Service[$::neutron::params::server_service],
}
service { $::neutron::params::server_service:
hasstatus => true,
hasrestart => true,
}
# Glance notifications
include glance::params
$glance_api_service = $::glance::params::api_service_name
$glance_registry_service = $::glance::params::registry_service_name
# Default value is 'image.localhost' for Glance
$glance_publisher_id = "image.${::hostname}"
glance_api_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$glance_api_service],
}
glance_api_config { 'DEFAULT/notification_driver':
value => 'messaging',
notify => Service[$glance_api_service],
}
glance_api_config { 'DEFAULT/default_publisher_id':
value => $glance_publisher_id,
notify => Service[$glance_api_service],
}
glance_registry_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$glance_registry_service],
}
glance_registry_config { 'DEFAULT/notification_driver':
value => 'messaging',
notify => Service[$glance_registry_service],
}
glance_registry_config { 'DEFAULT/default_publisher_id':
value => $glance_publisher_id,
notify => Service[$glance_registry_service],
}
service { [$glance_api_service, $glance_registry_service]:
hasstatus => true,
hasrestart => true,
}
# Heat notifications
include heat::params
$heat_api_service = $::heat::params::api_service_name
$heat_engine_service = $::heat::params::engine_service_name
heat_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$heat_api_service, $heat_engine_service],
}
heat_config { 'DEFAULT/notification_driver':
value => $driver,
notify => Service[$heat_api_service, $heat_engine_service],
}
service { $heat_api_service:
hasstatus => true,
hasrestart => true,
}
# The heat-engine service is managed by Pacemaker.
service { $heat_engine_service:
hasstatus => true,
hasrestart => true,
provider => 'pacemaker',
}
# OpenStack logs are useful for deriving HTTP metrics, so we enable them even

View File

@ -328,6 +328,20 @@ To make the collector collect statistics for MySQL declare the
class { 'lma_collector::collectd::mysql': }
```
### Collect OpenStack notifications
To make the collector collect notifications emitted by the OpenStack services
declare the `lma_collector::notifications::input` class:
```puppet
class { 'lma_collector::notifications::input':
topic => 'lma_notifications',
host => '127.0.0.1',
user => 'rabbit_user',
password => 'rabbit_password',
}
```
## Reference
### Classes
@ -356,6 +370,7 @@ Public Classes:
* [`lma_collector::collectd::hypervisor`](#class-lma_collectorcollectdhypervisor)
* [`lma_collector::collectd::pacemaker`](#class-lma_collectorcollectdpacemaker)
* [`lma_collector::collectd::mysql`](#class-lma_collectorcollectdmysql)
* [`lma_collector::notifications::input`](#class-lma_notificationsinput)
Private Classes:
@ -671,6 +686,27 @@ performance statistics of all the OSD daemons running on the host.
The collectd plugin used is a Python script. That script uses the `ceph`
command internally, so that command should be installed.
#### Class: `lma_collector::notifications::input`
Declare this class to make Heka collect the notifications emitted by the
OpenStack services on RabbitMQ.
The OpenStack services should be configured to send their notifications to the
same topic exchange as the one this class is configured with.
##### Parameters
* `topic`: *Required*. The topic exchange from where to read the notifications.
Valid options: a string.
* `host`: *Required*. The address of the RabbitMQ host. Valid options: a
string.
* `port`: *Optional*. The port the RabbitMQ host listens on. Valid options:
an integer. Default: `5672`.
* `user`: *Required*. The user to use to connect to RabbitMQ. Valid options: a
string.
* `password`: *Required*. The password to use to connect to RabbitMQ. Valid
options: a string.
#### Define: `lma_collector::logs::openstack`
Declare this type to create an Heka `logstreamer` that reads logs of an

View File

@ -1,39 +0,0 @@
# Copyright 2015 Mirantis, Inc.
#
# 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.
#
class lma_collector::notifications::cinder (
$topics = [],
$driver = $lma_collector::params::notification_driver,
) inherits lma_collector::params {
include lma_collector::service
validate_array($topics)
include cinder::params
cinder_config { 'DEFAULT/notification_topics':
value => join($topics, ','),
notify => Service[$::cinder::params::volume_service],
}
cinder_config { 'DEFAULT/notification_driver':
value => $driver,
notify => Service[$::cinder::params::volume_service],
}
service { $::cinder::params::volume_service:
hasstatus => true,
hasrestart => true,
}
}

View File

@ -1,42 +0,0 @@
# Copyright 2015 Mirantis, Inc.
#
# 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.
#
class lma_collector::notifications::compute (
$topics = [],
$driver = $lma_collector::params::notification_driver,
) inherits lma_collector::params {
include lma_collector::service
validate_array($topics)
include nova::params
nova_config { 'DEFAULT/notification_topics':
value => join($topics, ','),
notify => Service[$::nova::params::compute_service_name],
}
nova_config { 'DEFAULT/notification_driver':
value => $driver,
notify => Service[$::nova::params::compute_service_name],
}
nova_config { 'DEFAULT/notify_on_state_change':
value => 'vm_and_task_state',
notify => Service[$::nova::params::compute_service_name],
}
service { $::nova::params::compute_service_name:
hasstatus => true,
hasrestart => true,
}
}

View File

@ -1,237 +0,0 @@
# Copyright 2015 Mirantis, Inc.
#
# 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.
#
class lma_collector::notifications::controller (
$host = $lma_collector::params::rabbitmq_host,
$port = $lma_collector::params::rabbitmq_port,
$user = $lma_collector::params::rabbitmq_user,
$password = $lma_collector::params::rabbitmq_password,
$driver = $lma_collector::params::notification_driver,
$topics = [],
) inherits lma_collector::params {
include lma_collector::service
validate_array($topics)
$notification_topics = join($topics, ',')
# We need to pick one exchange and we settled on 'nova'. The default
# exchange ("") doesn't work because Heka would fail to create the queue in
# case it doesn't exist yet.
$exchange = 'nova'
# Workaround for bug #1503251
$plugin_can_exit = true
heka::decoder::sandbox { 'notification':
config_dir => $lma_collector::params::config_dir,
filename => "${lma_collector::params::plugins_dir}/decoders/notification.lua" ,
config => {
include_full_notification => false
},
notify => Class['lma_collector::service'],
}
heka::input::amqp { 'openstack_info':
config_dir => $lma_collector::params::config_dir,
decoder => 'notification',
user => $user,
password => $password,
host => $host,
port => $port,
exchange => $exchange,
exchange_durability => false,
exchange_auto_delete => false,
queue_auto_delete => false,
exchange_type => 'topic',
queue => "${lma_collector::params::lma_topic}.info",
routing_key => "${lma_collector::params::lma_topic}.info",
can_exit => $plugin_can_exit,
notify => Class['lma_collector::service'],
}
heka::input::amqp { 'openstack_error':
config_dir => $lma_collector::params::config_dir,
decoder => 'notification',
user => $user,
password => $password,
host => $host,
port => $port,
exchange => $exchange,
exchange_durability => false,
exchange_auto_delete => false,
queue_auto_delete => false,
exchange_type => 'topic',
queue => "${lma_collector::params::lma_topic}.error",
routing_key => "${lma_collector::params::lma_topic}.error",
can_exit => $plugin_can_exit,
notify => Class['lma_collector::service'],
}
heka::input::amqp { 'openstack_warn':
config_dir => $lma_collector::params::config_dir,
decoder => 'notification',
user => $user,
password => $password,
host => $host,
port => $port,
exchange => $exchange,
exchange_durability => false,
exchange_auto_delete => false,
queue_auto_delete => false,
exchange_type => 'topic',
queue => "${lma_collector::params::lma_topic}.warn",
routing_key => "${lma_collector::params::lma_topic}.warn",
can_exit => $plugin_can_exit,
notify => Class['lma_collector::service'],
}
# Nova
include nova::params
nova_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$::nova::params::api_service_name, $::nova::params::conductor_service_name, $::nova::params::scheduler_service_name],
}
nova_config { 'DEFAULT/notification_driver':
value => $driver,
notify => Service[$::nova::params::api_service_name, $::nova::params::conductor_service_name, $::nova::params::scheduler_service_name],
}
nova_config { 'DEFAULT/notify_on_state_change':
value => 'vm_and_task_state',
notify => Service[$::nova::params::api_service_name, $::nova::params::conductor_service_name, $::nova::params::scheduler_service_name],
}
service { [$::nova::params::api_service_name, $::nova::params::conductor_service_name, $::nova::params::scheduler_service_name]:
hasstatus => true,
hasrestart => true,
}
# Cinder
include cinder::params
cinder_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$::cinder::params::api_service, $::cinder::params::scheduler_service],
}
cinder_config { 'DEFAULT/notification_driver':
value => $driver,
notify => Service[$::cinder::params::api_service, $::cinder::params::scheduler_service],
}
service { [$::cinder::params::api_service, $::cinder::params::scheduler_service]:
hasstatus => true,
hasrestart => true,
}
# Keystone
include keystone::params
keystone_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$::keystone::params::service_name],
}
keystone_config { 'DEFAULT/notification_driver':
value => $driver,
notify => Service[$::keystone::params::service_name],
}
service { $::keystone::params::service_name:
hasstatus => true,
hasrestart => true,
}
# Neutron
include neutron::params
neutron_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$::neutron::params::server_service],
}
neutron_config { 'DEFAULT/notification_driver':
value => $driver,
notify => Service[$::neutron::params::server_service],
}
service { $::neutron::params::server_service:
hasstatus => true,
hasrestart => true,
}
# Glance
include glance::params
# Default value is 'image.localhost' for Glance
$glance_publisher_id = "image.${::hostname}"
glance_api_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$::glance::params::api_service_name],
}
glance_api_config { 'DEFAULT/notification_driver':
value => $driver,
notify => Service[$::glance::params::api_service_name],
}
glance_api_config { 'DEFAULT/default_publisher_id':
value => $glance_publisher_id,
notify => Service[$::glance::params::api_service_name],
}
glance_registry_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => Service[$::glance::params::registry_service_name],
}
glance_registry_config { 'DEFAULT/notification_driver':
value => $driver,
notify => Service[$::glance::params::registry_service_name],
}
glance_registry_config { 'DEFAULT/default_publisher_id':
value => $glance_publisher_id,
notify => Service[$::glance::params::registry_service_name],
}
service { [$::glance::params::api_service_name, $::glance::params::registry_service_name]:
hasstatus => true,
hasrestart => true,
}
# Heat
include heat::params
# Note: since the heat-engine process is managed by pacemaker, traditional
# status/restart scripts don't work (hijacked by a pcs resource not
# used in lma module).
# We leverage the Heat capacity to reload its configuration by handling the
# signal SIGUSR1.
$reload_heat_engine = 'reload-heat-engine-config-with-SIGUSR1'
# TODO: turn this workaround into a type/provider resource or wait until
# heat-engine is no longer managed by pacemaker and rollback to a traditional
# service restart.
exec { $reload_heat_engine:
command => '/usr/bin/pkill -10 heat-engine',
refreshonly => true,
}
heat_config { 'DEFAULT/notification_topics':
value => $notification_topics,
notify => [Service[$::heat::params::api_service_name], Exec[$reload_heat_engine]],
}
heat_config { 'DEFAULT/notification_driver':
value => $driver,
notify => [Service[$::heat::params::api_service_name], Exec[$reload_heat_engine]],
}
service { [$::heat::params::api_service_name]:
hasstatus => true,
hasrestart => true,
}
}

View File

@ -0,0 +1,76 @@
# Copyright 2015 Mirantis, Inc.
#
# 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.
#
class lma_collector::notifications::input (
$topic,
$user,
$password,
$host,
$port = $lma_collector::params::rabbitmq_port,
) inherits lma_collector::params {
include lma_collector::service
validate_string($topic)
validate_string($user)
validate_string($password)
validate_string($host)
validate_integer($port)
# We need to pick one exchange and we settled on 'nova'. The default
# exchange ("") doesn't work because Heka would fail to create the queue in
# case it doesn't exist yet.
$exchange = 'nova'
heka::decoder::sandbox { 'notification':
config_dir => $lma_collector::params::config_dir,
filename => "${lma_collector::params::plugins_dir}/decoders/notification.lua" ,
config => {
include_full_notification => false
},
notify => Class['lma_collector::service'],
}
create_resources(
heka::input::amqp,
{
'openstack_info' => {
queue => "${topic}.info",
routing_key => "${topic}.info",
},
'openstack_warn' => {
queue => "${topic}.warn",
routing_key => "${topic}.warn",
},
'openstack_error' => {
queue => "${topic}.error",
routing_key => "${topic}.error",
},
},
{
config_dir => $lma_collector::params::config_dir,
decoder => 'notification',
user => $user,
password => $password,
host => $host,
port => $port,
exchange => $exchange,
exchange_durability => false,
exchange_auto_delete => false,
queue_auto_delete => false,
exchange_type => 'topic',
notify => Class['lma_collector::service'],
}
)
}

View File

@ -84,14 +84,7 @@ class lma_collector::params {
$hekad_max_timer_inject = 10
# Parameters for OpenStack notifications
$rabbitmq_host = false
$rabbitmq_port = '5672'
$rabbitmq_user = ''
$rabbitmq_password = ''
$rabbitmq_exchange = ''
$lma_topic = 'lma_notifications'
$openstack_topic = 'notifications'
$notification_driver = 'messaging'
# collectd parameters
$collectd_port = '8325'

View File

@ -23,13 +23,6 @@
{"name": "puppet/collectd", "version_requirement": ">= 4.1.2"},
{"name": "puppetlabs/apache", "version_requirement": ">= 1.4.0"},
{"name": "puppetlabs/inifile", "version_requirement": ">= 1.4.2"},
{"name": "puppetlabs/stdlib", "version_requirement": "4.x"},
{"name": "openstack/cinder", "version_requirement": "7.x"},
{"name": "openstack/glance", "version_requirement": "7.x"},
{"name": "openstack/heat", "version_requirement": "7.x"},
{"name": "openstack/keystone", "version_requirement": "7.x"},
{"name": "openstack/neutron", "version_requirement": "7.x"},
{"name": "openstack/nova", "version_requirement": "7.x"},
{"name": "openstack/openstacklib", "version_requirement": "7.x"}
{"name": "puppetlabs/stdlib", "version_requirement": "4.x"}
]
}

View File

@ -0,0 +1,32 @@
# Copyright 2016 Mirantis, Inc.
#
# 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.
require 'spec_helper'
describe 'lma_collector::notifications::input' do
let(:facts) do
{:kernel => 'Linux', :operatingsystem => 'Ubuntu',
:osfamily => 'Debian'}
end
describe 'with localhost server' do
let(:params) do
{ :host => 'localhost', :topic => 'foo', :user => 'bob',
:password => 'secret' }
end
it { is_expected.to contain_heka__decoder__sandbox('notification') }
it { is_expected.to contain_heka__input__amqp('openstack_info') }
it { is_expected.to contain_heka__input__amqp('openstack_warn') }
it { is_expected.to contain_heka__input__amqp('openstack_error') }
end
end