Merge "Backward-compatible commit for packaging of fuel-library"
This commit is contained in:
commit
db5f39e96e
17
debian/changelog
vendored
Normal file
17
debian/changelog
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
fuel-library6.1 (6.0.0-1) precise; urgency=low
|
||||
|
||||
* Update code from upstream
|
||||
|
||||
-- Igor Kalnitsky <ikalnitsky@mirantis.com> Wed, 26 Nov 2014 19:49:00 +0200
|
||||
|
||||
fuel-library6.1 (0.0.1-ubuntu1) precise; urgency=low
|
||||
|
||||
* Update code from upstream
|
||||
|
||||
-- OSCI Jenkins <dburmistrov@mirantis.com> Wed, 03 Sep 2014 15:20:13 +0400
|
||||
|
||||
fuel-library6.1 (0.0.1) unstable; urgency=low
|
||||
|
||||
* Initial release.
|
||||
|
||||
-- Mirantis Product <product@mirantis.com> Tue, 20 Aug 2013 22:20:46 +0400
|
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@ -0,0 +1 @@
|
||||
7
|
18
debian/control
vendored
Normal file
18
debian/control
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
Source: fuel-library6.1
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Mirantis Product <product@mirantis.com>
|
||||
Build-Depends: debhelper (>= 7), python-all
|
||||
Standards-Version: 3.9.2
|
||||
|
||||
Package: fuel-ha-utils
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}, python-keystoneclient, python-neutronclient
|
||||
Description: Fuel Library HA utils
|
||||
.
|
||||
|
||||
Package: fuel-misc
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: Misc Fuel library scripts
|
||||
.
|
5
debian/fuel-ha-utils.install
vendored
Normal file
5
debian/fuel-ha-utils.install
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
files/fuel-ha-utils/ocf/* /usr/lib/ocf/resource.d/fuel
|
||||
files/fuel-ha-utils/tools/q-agent-cleanup.py /usr/bin
|
||||
files/fuel-ha-utils/tools/wsrepclustercheckrc /etc
|
||||
files/fuel-ha-utils/tools/clustercheck /usr/bin
|
||||
|
2
debian/fuel-misc.install
vendored
Normal file
2
debian/fuel-misc.install
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
files/fuel-misc/haproxy-status.sh /usr/bin
|
||||
|
10
debian/rules
vendored
Executable file
10
debian/rules
vendored
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@ --with python2
|
||||
|
||||
override_dh_fixperms:
|
||||
chmod 755 debian/fuel-ha-utils/usr/lib/ocf/resource.d/fuel/*
|
||||
dh_fixperms
|
||||
|
||||
|
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
@ -15,6 +15,6 @@ class ceilometer_ha::agent::central inherits ceilometer::agent::central {
|
||||
'timeout' => '360',
|
||||
},
|
||||
},
|
||||
ocf_script_file => 'cluster/ocf/ceilometer-agent-central',
|
||||
ocf_script_file => 'cluster/ocf/ceilometer-agent-central',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,6 @@ class ceilometer_ha::alarm::evaluator inherits ceilometer::alarm::evaluator {
|
||||
'timeout' => '360',
|
||||
},
|
||||
},
|
||||
ocf_script_file => 'cluster/ocf/ceilometer-alarm-evaluator',
|
||||
ocf_script_file => 'cluster/ocf/ceilometer-alarm-evaluator',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ define cluster::corosync::cs_service (
|
||||
}
|
||||
|
||||
# OCF script for pacemaker
|
||||
file { $ocf_script :
|
||||
file { $ocf_script :
|
||||
path => "/usr/lib/ocf/resource.d/fuel/${ocf_script}",
|
||||
mode => '0755',
|
||||
owner => root,
|
||||
@ -55,11 +55,13 @@ define cluster::corosync::cs_service (
|
||||
}
|
||||
}
|
||||
}
|
||||
File[$ocf_script] -> Cs_resource["p_${service_name}"] -> Service[$service_true_title]
|
||||
} else {
|
||||
File[$ocf_script] -> Service[$service_true_title]
|
||||
File <| title == $ocf_script |> -> Cs_resource["p_${service_name}"]
|
||||
Cs_resource["p_${service_name}"] -> Service[$service_true_title]
|
||||
}
|
||||
else
|
||||
{
|
||||
File <| title == $ocf_script |> -> Service[$service_true_title]
|
||||
}
|
||||
|
||||
if ! $package_name {
|
||||
warning('Cluster::corosync::cs_service: Without package definition can\'t protect service for autostart correctly.')
|
||||
} else {
|
||||
|
@ -15,9 +15,9 @@ class cluster::haproxy_ocf (
|
||||
path =>'/usr/lib/ocf/resource.d/fuel/ns_haproxy',
|
||||
mode => '0755',
|
||||
owner => root,
|
||||
group => root,
|
||||
source => 'puppet:///modules/cluster/ocf/ns_haproxy',
|
||||
}
|
||||
group => root,
|
||||
source => 'puppet:///modules/cluster/ocf/ns_haproxy',
|
||||
}
|
||||
Anchor['haproxy'] -> File['haproxy-ocf']
|
||||
File<| title == 'ocf-fuel-path' |> -> File['haproxy-ocf']
|
||||
|
||||
@ -81,7 +81,7 @@ class cluster::haproxy_ocf (
|
||||
if ($::osfamily == 'Debian') {
|
||||
file { '/etc/default/haproxy':
|
||||
content => 'ENABLED=0',
|
||||
} -> File['haproxy-ocf']
|
||||
} -> File['haproxy-ocf']
|
||||
if $::operatingsystem == 'Ubuntu' {
|
||||
file { '/etc/init/haproxy.override':
|
||||
ensure => 'present',
|
||||
@ -98,6 +98,7 @@ class cluster::haproxy_ocf (
|
||||
enable => false,
|
||||
} -> File['haproxy-ocf']
|
||||
|
||||
|
||||
sysctl::value { 'net.ipv4.ip_nonlocal_bind':
|
||||
value => '1'
|
||||
} ->
|
||||
|
@ -6,7 +6,7 @@ class cluster::neutron () {
|
||||
File<| title == 'ocf-mirantis-path' |> ->
|
||||
Package['neutron'] ->
|
||||
|
||||
file {'q-agent-cleanup.py':
|
||||
file {'q-agent-cleanup.py':
|
||||
path => '/usr/bin/q-agent-cleanup.py',
|
||||
mode => '0755',
|
||||
owner => root,
|
||||
@ -25,4 +25,4 @@ class cluster::neutron () {
|
||||
if !defined(Package['lsof']) {
|
||||
package { 'lsof': }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ define cluster::virtual_ip (
|
||||
){
|
||||
$vip_name = "vip__${key}"
|
||||
|
||||
File['ns-ipaddr2-ocf'] -> Cs_resource[$vip_name]
|
||||
File<| title == 'ns-ipaddr2-ocf' |> -> Cs_resource[$vip_name]
|
||||
|
||||
cs_resource { $vip_name:
|
||||
ensure => present,
|
||||
|
@ -4,12 +4,13 @@ class docker::dockerctl (
|
||||
$config_dir = '/etc/dockerctl',
|
||||
$profile_dir = '/etc/profile.d',
|
||||
$admin_ipaddress = $::fuel_settings['ADMIN_NETWORK']['ipaddress'],
|
||||
$docker_engine = 'native',
|
||||
$release,
|
||||
$production,
|
||||
) {
|
||||
|
||||
# Make sure we have needed directories
|
||||
file { [$bin_dir, $share_dir, $config_dir, $profile_dir]:
|
||||
file { [$bin_dir, $share_dir, $config_dir, $profile_dir]:
|
||||
ensure => directory;
|
||||
}
|
||||
|
||||
@ -18,7 +19,7 @@ class docker::dockerctl (
|
||||
mode => 0755,
|
||||
content => template("docker/dockerctl.erb");
|
||||
}
|
||||
|
||||
|
||||
file { "$profile_dir/dockerctl.sh":
|
||||
content => template("docker/dockerctl-alias.sh.erb"),
|
||||
owner => 'root',
|
||||
@ -29,7 +30,7 @@ class docker::dockerctl (
|
||||
mode => 0755,
|
||||
content => template("docker/get_service_credentials.py.erb")
|
||||
}
|
||||
file { "$share_dir/functions":
|
||||
file { "$share_dir/functions.sh":
|
||||
mode => 0644,
|
||||
content => template("docker/functions.sh.erb")
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
confdir="<%= @config_dir %>"
|
||||
. "$confdir/config"
|
||||
. "<%= @share_dir %>/functions"
|
||||
. "<%= @share_dir %>/functions.sh"
|
||||
DEBUG=true
|
||||
|
||||
#Sets var nonopts
|
||||
|
@ -191,13 +191,13 @@ class galera (
|
||||
},
|
||||
}
|
||||
Anchor['galera'] ->
|
||||
File['mysql-wss-ocf'] ->
|
||||
File['mysql-wss-ocf'] ->
|
||||
Cs_resource["p_${service_name}"] ->
|
||||
Service['mysql'] ->
|
||||
Exec['wait-for-synced-state']
|
||||
} else {
|
||||
Anchor['galera'] ->
|
||||
File['mysql-wss-ocf'] ->
|
||||
File['mysql-wss-ocf'] ->
|
||||
Service['mysql']
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ class galera (
|
||||
|
||||
File<| title == 'ocf-fuel-path' |> -> File['mysql-wss-ocf']
|
||||
|
||||
Package['MySQL-server', 'galera'] -> File['mysql-wss-ocf']
|
||||
Package['MySQL-server', 'galera'] -> File['mysql-wss-ocf']
|
||||
|
||||
tweaks::ubuntu_service_override { 'mysql':
|
||||
package_name => 'MySQL-server',
|
||||
|
@ -1,14 +0,0 @@
|
||||
class haproxy::status (
|
||||
$haproxy_socket = '/var/lib/haproxy/stats',
|
||||
$file = '/usr/local/bin/haproxy-status',
|
||||
) {
|
||||
|
||||
file { $file :
|
||||
ensure => present,
|
||||
mode => '0755',
|
||||
owner => 'root',
|
||||
group => 'root',
|
||||
content => template('haproxy/haproxy-status.sh.erb'),
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
class heat_ha::engine inherits heat::engine {
|
||||
$primitive_type = 'heat-engine'
|
||||
|
||||
if $::osfamily == 'RedHat' {
|
||||
$ocf_script_template = 'heat/heat_engine_centos.ocf.erb'
|
||||
} else {
|
||||
$ocf_script_template = 'heat/heat_engine_ubuntu.ocf.erb'
|
||||
if $::osfamily == 'RedHat' {
|
||||
$ocf_script_template = 'heat/heat_engine_centos.ocf.erb'
|
||||
} else {
|
||||
$ocf_script_template = 'heat/heat_engine_ubuntu.ocf.erb'
|
||||
}
|
||||
|
||||
$metadata = {
|
||||
|
@ -52,6 +52,7 @@ class l23network (
|
||||
Anchor <| title == 'l23network::l2::centos_upndown_scripts' |> -> Anchor['l23network::init']
|
||||
}
|
||||
|
||||
|
||||
Anchor['l23network::l2::init'] -> Anchor['l23network::init']
|
||||
anchor { 'l23network::init': }
|
||||
|
||||
|
@ -47,6 +47,7 @@ class { 'docker::dockerctl':
|
||||
release => $::fuel_version['VERSION']['release'],
|
||||
production => $production,
|
||||
admin_ipaddress => $::fuel_settings['ADMIN_NETWORK']['ipaddress'],
|
||||
docker_engine => 'native',
|
||||
}
|
||||
|
||||
class { "docker":
|
||||
|
76
deployment/puppet/openstack/files/clustercheck
Normal file
76
deployment/puppet/openstack/files/clustercheck
Normal file
@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script to make a proxy (ie HAProxy) capable of monitoring Percona XtraDB Cluster nodes properly
|
||||
#
|
||||
# Author: Olaf van Zandwijk <olaf.vanzandwijk@nedap.com>
|
||||
# Author: Raghavendra Prabhu <raghavendra.prabhu@percona.com>
|
||||
#
|
||||
# Documentation and download: https://github.com/olafz/percona-clustercheck
|
||||
#
|
||||
# Based on the original script from Unai Rodriguez
|
||||
#
|
||||
|
||||
if [[ $1 == '-h' || $1 == '--help' ]];then
|
||||
echo "Usage: $0 <user> <pass> <available_when_donor=0|1> <log_file> <available_when_readonly=0|1> <defaults_extra_file>"
|
||||
exit
|
||||
fi
|
||||
|
||||
[ -f /etc/wsrepclustercheckrc ] && . /etc/wsrepclustercheckrc
|
||||
|
||||
if [[ -r $DEFAULTS_EXTRA_FILE ]];then
|
||||
MYSQL_CMDLINE="mysql --defaults-extra-file=$DEFAULTS_EXTRA_FILE -nNE --connect-timeout=$TIMEOUT \
|
||||
--user=${MYSQL_USERNAME} --password=${MYSQL_PASSWORD} -h ${MYSQL_HOST} -P ${MYSQL_PORT}"
|
||||
else
|
||||
MYSQL_CMDLINE="mysql -nNE --connect-timeout=$TIMEOUT --user=${MYSQL_USERNAME} --password=${MYSQL_PASSWORD} \
|
||||
-h ${MYSQL_HOST} -P ${MYSQL_PORT}"
|
||||
fi
|
||||
#
|
||||
# Perform the query to check the wsrep_local_state
|
||||
#
|
||||
WSREP_STATUS=$($MYSQL_CMDLINE -e "SHOW STATUS LIKE 'wsrep_local_state';" \
|
||||
2>${ERR_FILE} | tail -1 2>>${ERR_FILE})
|
||||
|
||||
if [[ "${WSREP_STATUS}" == "4" ]] || [[ "${WSREP_STATUS}" == "2" && ${AVAILABLE_WHEN_DONOR} == 1 ]]
|
||||
then
|
||||
# Check only when set to 0 to avoid latency in response.
|
||||
if [[ $AVAILABLE_WHEN_READONLY -eq 0 ]];then
|
||||
READ_ONLY=$($MYSQL_CMDLINE -e "SHOW GLOBAL VARIABLES LIKE 'read_only';" \
|
||||
2>${ERR_FILE} | tail -1 2>>${ERR_FILE})
|
||||
|
||||
if [[ "${READ_ONLY}" == "ON" ]];then
|
||||
# Percona XtraDB Cluster node local state is 'Synced', but it is in
|
||||
# read-only mode. The variable AVAILABLE_WHEN_READONLY is set to 0.
|
||||
# => return HTTP 503
|
||||
# Shell return-code is 1
|
||||
echo -en "HTTP/1.1 503 Service Unavailable\r\n"
|
||||
echo -en "Content-Type: text/plain\r\n"
|
||||
echo -en "Connection: close\r\n"
|
||||
echo -en "Content-Length: 43\r\n"
|
||||
echo -en "\r\n"
|
||||
echo -en "Percona XtraDB Cluster Node is read-only.\r\n"
|
||||
sleep 0.1
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
# Percona XtraDB Cluster node local state is 'Synced' => return HTTP 200
|
||||
# Shell return-code is 0
|
||||
echo -en "HTTP/1.1 200 OK\r\n"
|
||||
echo -en "Content-Type: text/plain\r\n"
|
||||
echo -en "Connection: close\r\n"
|
||||
echo -en "Content-Length: 40\r\n"
|
||||
echo -en "\r\n"
|
||||
echo -en "Percona XtraDB Cluster Node is synced.\r\n"
|
||||
sleep 0.1
|
||||
exit 0
|
||||
else
|
||||
# Percona XtraDB Cluster node local state is not 'Synced' => return HTTP 503
|
||||
# Shell return-code is 1
|
||||
echo -en "HTTP/1.1 503 Service Unavailable\r\n"
|
||||
echo -en "Content-Type: text/plain\r\n"
|
||||
echo -en "Connection: close\r\n"
|
||||
echo -en "Content-Length: 44\r\n"
|
||||
echo -en "\r\n"
|
||||
echo -en "Percona XtraDB Cluster Node is not synced.\r\n"
|
||||
sleep 0.1
|
||||
exit 1
|
||||
fi
|
@ -81,11 +81,19 @@ class openstack::galera::status (
|
||||
}
|
||||
}
|
||||
|
||||
file { '/usr/local/bin/clustercheck':
|
||||
file { '/etc/wsrepclustercheckrc':
|
||||
content => template('openstack/galera_clustercheck.erb'),
|
||||
mode => '0755',
|
||||
}
|
||||
|
||||
file { '/usr/bin/clustercheck':
|
||||
mode => '0755',
|
||||
owner => root,
|
||||
group => root,
|
||||
source => "puppet:///modules/openstack/clustercheck",
|
||||
require => File['/etc/wsrepclustercheckrc'],
|
||||
}
|
||||
|
||||
augeas { 'galeracheck':
|
||||
context => '/files/etc/services',
|
||||
changes => [
|
||||
@ -94,7 +102,7 @@ class openstack::galera::status (
|
||||
"set /files/etc/services/service-name[port = '${port}']/protocol tcp",
|
||||
"set /files/etc/services/service-name[port = '${port}']/#comment 'Galera Cluster Check'",
|
||||
],
|
||||
require => File['/usr/local/bin/clustercheck'],
|
||||
require => File['/usr/bin/clustercheck'],
|
||||
}
|
||||
|
||||
$group = $::osfamily ? {
|
||||
@ -109,10 +117,10 @@ class openstack::galera::status (
|
||||
port => $port,
|
||||
cps => '512 10',
|
||||
per_source => 'UNLIMITED',
|
||||
server => '/usr/local/bin/clustercheck',
|
||||
server => '/usr/bin/clustercheck',
|
||||
user => 'nobody',
|
||||
group => $group,
|
||||
flags => 'IPv4',
|
||||
require => File['/usr/local/bin/clustercheck'],
|
||||
require => File['/usr/bin/clustercheck'],
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,3 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script to make a proxy (ie HAProxy) capable of monitoring Percona XtraDB Cluster nodes properly
|
||||
#
|
||||
# Author: Olaf van Zandwijk <olaf.vanzandwijk@nedap.com>
|
||||
# Author: Raghavendra Prabhu <raghavendra.prabhu@percona.com>
|
||||
#
|
||||
# Documentation and download: https://github.com/olafz/percona-clustercheck
|
||||
#
|
||||
# Based on the original script from Unai Rodriguez
|
||||
#
|
||||
|
||||
if [[ $1 == '-h' || $1 == '--help' ]];then
|
||||
echo "Usage: $0 <user> <pass> <available_when_donor=0|1> <log_file> <available_when_readonly=0|1> <defaults_extra_file>"
|
||||
exit
|
||||
fi
|
||||
|
||||
MYSQL_USERNAME="<%= @status_user %>"
|
||||
MYSQL_PASSWORD="<%= @status_password %>"
|
||||
@ -26,61 +10,3 @@ DEFAULTS_EXTRA_FILE=${6:-/etc/my.cnf}
|
||||
|
||||
#Timeout exists for instances where mysqld may be hung
|
||||
TIMEOUT=<%= @backend_timeout %>
|
||||
|
||||
if [[ -r $DEFAULTS_EXTRA_FILE ]];then
|
||||
MYSQL_CMDLINE="mysql --defaults-extra-file=$DEFAULTS_EXTRA_FILE -nNE --connect-timeout=$TIMEOUT \
|
||||
--user=${MYSQL_USERNAME} --password=${MYSQL_PASSWORD} -h ${MYSQL_HOST} -P ${MYSQL_PORT}"
|
||||
else
|
||||
MYSQL_CMDLINE="mysql -nNE --connect-timeout=$TIMEOUT --user=${MYSQL_USERNAME} --password=${MYSQL_PASSWORD} \
|
||||
-h ${MYSQL_HOST} -P ${MYSQL_PORT}"
|
||||
fi
|
||||
#
|
||||
# Perform the query to check the wsrep_local_state
|
||||
#
|
||||
WSREP_STATUS=$($MYSQL_CMDLINE -e "SHOW STATUS LIKE 'wsrep_local_state';" \
|
||||
2>${ERR_FILE} | tail -1 2>>${ERR_FILE})
|
||||
|
||||
if [[ "${WSREP_STATUS}" == "4" ]] || [[ "${WSREP_STATUS}" == "2" && ${AVAILABLE_WHEN_DONOR} == 1 ]]
|
||||
then
|
||||
# Check only when set to 0 to avoid latency in response.
|
||||
if [[ $AVAILABLE_WHEN_READONLY -eq 0 ]];then
|
||||
READ_ONLY=$($MYSQL_CMDLINE -e "SHOW GLOBAL VARIABLES LIKE 'read_only';" \
|
||||
2>${ERR_FILE} | tail -1 2>>${ERR_FILE})
|
||||
|
||||
if [[ "${READ_ONLY}" == "ON" ]];then
|
||||
# Percona XtraDB Cluster node local state is 'Synced', but it is in
|
||||
# read-only mode. The variable AVAILABLE_WHEN_READONLY is set to 0.
|
||||
# => return HTTP 503
|
||||
# Shell return-code is 1
|
||||
echo -en "HTTP/1.1 503 Service Unavailable\r\n"
|
||||
echo -en "Content-Type: text/plain\r\n"
|
||||
echo -en "Connection: close\r\n"
|
||||
echo -en "Content-Length: 43\r\n"
|
||||
echo -en "\r\n"
|
||||
echo -en "Percona XtraDB Cluster Node is read-only.\r\n"
|
||||
sleep 0.1
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
# Percona XtraDB Cluster node local state is 'Synced' => return HTTP 200
|
||||
# Shell return-code is 0
|
||||
echo -en "HTTP/1.1 200 OK\r\n"
|
||||
echo -en "Content-Type: text/plain\r\n"
|
||||
echo -en "Connection: close\r\n"
|
||||
echo -en "Content-Length: 40\r\n"
|
||||
echo -en "\r\n"
|
||||
echo -en "Percona XtraDB Cluster Node is synced.\r\n"
|
||||
sleep 0.1
|
||||
exit 0
|
||||
else
|
||||
# Percona XtraDB Cluster node local state is not 'Synced' => return HTTP 503
|
||||
# Shell return-code is 1
|
||||
echo -en "HTTP/1.1 503 Service Unavailable\r\n"
|
||||
echo -en "Content-Type: text/plain\r\n"
|
||||
echo -en "Connection: close\r\n"
|
||||
echo -en "Content-Length: 44\r\n"
|
||||
echo -en "\r\n"
|
||||
echo -en "Percona XtraDB Cluster Node is not synced.\r\n"
|
||||
sleep 0.1
|
||||
exit 1
|
||||
fi
|
||||
|
@ -0,0 +1,22 @@
|
||||
#FIXME(aglarendil): this fact is a temporary workaround
|
||||
#FIXME: It should be removed after switching to
|
||||
#FIXME: packages
|
||||
require 'facter'
|
||||
Facter.add('fuel_pkgs_exist') do
|
||||
setcode do
|
||||
rv = 'false'
|
||||
case Facter.value('osfamily')
|
||||
when /(?i)(debian)/
|
||||
pkg_grep_cmd = "apt-cache search"
|
||||
when /(?i)(redhat)/
|
||||
pkg_grep_cmd = "yum list | grep"
|
||||
end
|
||||
|
||||
out1=Facter::Util::Resolution.exec("#{pkg_grep_cmd} fuel-ha-utils")
|
||||
out2=Facter::Util::Resolution.exec("#{pkg_grep_cmd} fuel-misc")
|
||||
if !out1.to_s.empty? and !out2.to_s.empty?
|
||||
rv = 'true'
|
||||
end
|
||||
rv
|
||||
end
|
||||
end
|
@ -0,0 +1,10 @@
|
||||
notice('MODULAR: fuel_pkgs.pp')
|
||||
|
||||
$fuel_packages=['fuel-ha-utils','fuel-misc']
|
||||
notify{"this is the place where ${fuel_packages} should be installed":}
|
||||
#FIXME(algarendil): remove this if when we switch to pkg-based stuff
|
||||
if $::fuel_pkgs_exist == 'true'
|
||||
{
|
||||
package {$fuel_packages: ensure => latest }
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
- id: fuel_pkgs
|
||||
type: puppet
|
||||
groups: [primary-controller, controller, cinder, cinder-vmware, compute, ceph-osd, zabbix-server, primary-mongo, mongo]
|
||||
requires: [deploy_start]
|
||||
required_for: [hiera]
|
||||
parameters:
|
||||
puppet_manifest: /etc/puppet/modules/osnailyfacter/modular/fuel_pkgs/fuel_pkgs.pp
|
||||
puppet_modules: /etc/puppet/modules
|
||||
timeout: 600
|
@ -28,6 +28,3 @@ class { 'puppet::pull' :
|
||||
}
|
||||
|
||||
$deployment_mode = hiera('deployment_mode')
|
||||
if ($deployment_mode == 'ha') or ($deployment_mode == 'ha_compact') {
|
||||
include haproxy::status
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ if $operatingsystem == 'Ubuntu' {
|
||||
content => template('cluster/conntrackd.conf.erb'),
|
||||
} ->
|
||||
|
||||
file { '/usr/lib/ocf/resource.d/fuel/ns_conntrackd':
|
||||
file { '/usr/lib/ocf/resource.d/fuel/ns_conntrackd':
|
||||
mode => '0755',
|
||||
owner => root,
|
||||
group => root,
|
||||
|
123
files/fuel-docker-utils/dockerctl
Normal file
123
files/fuel-docker-utils/dockerctl
Normal file
@ -0,0 +1,123 @@
|
||||
#!/bin/bash
|
||||
# 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.
|
||||
|
||||
|
||||
confdir="/etc/dockerctl"
|
||||
. "$confdir/config"
|
||||
. "/usr/share/dockerctl/functions.sh"
|
||||
DEBUG=true
|
||||
|
||||
#Sets var nonopts
|
||||
declare -a nonopts
|
||||
parse_options "$@"
|
||||
set -- "${nonopts[@]}"
|
||||
|
||||
if [ -z "$1" ] || [ "$1" = "help" ]; then
|
||||
echo "Please specify a command."
|
||||
show_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] || [ "$2" = "all" ]; then
|
||||
container="all"
|
||||
else
|
||||
container=$2
|
||||
fi
|
||||
|
||||
container_seq=$CONTAINER_SEQUENCE
|
||||
|
||||
if [ "$1" == "build" ]; then
|
||||
if [ "$container" = "storage" ]; then
|
||||
build_storage_containers
|
||||
run_storage_containers
|
||||
elif [ "$container" = "all" ];then
|
||||
#Step 1: prepare storage containers
|
||||
build_storage_containers
|
||||
run_storage_containers
|
||||
|
||||
#Prepare iptables just in case ICC is broken
|
||||
allow_all_docker_traffic
|
||||
|
||||
#Step 2: Launch all in order, checking each one
|
||||
for service in $container_seq; do
|
||||
start_container $service
|
||||
check_ready $service
|
||||
done
|
||||
else
|
||||
start_container $container
|
||||
fi
|
||||
elif [ "$1" == "start" ]; then
|
||||
if [ "$container" = "all" ];then
|
||||
for service in $container_seq; do
|
||||
start_container $service
|
||||
check_ready $service
|
||||
sleep 4
|
||||
done
|
||||
else
|
||||
shift 2
|
||||
start_container $container $@
|
||||
if ! [[ "$@" =~ "--attach" ]]; then
|
||||
check_ready $container
|
||||
fi
|
||||
fi
|
||||
elif [ "$1" == "check" ]; then
|
||||
if [ "$container" = "all" ];then
|
||||
exit_code=0
|
||||
for service in $container_seq; do
|
||||
check_ready $service || exit_code=1
|
||||
done
|
||||
exit $exit_code
|
||||
else
|
||||
check_ready $container
|
||||
fi
|
||||
elif [ "$1" == "list" ]; then
|
||||
shift 1
|
||||
list_containers "$@"
|
||||
elif [ "$1" == "copy" ]; then
|
||||
shift 1
|
||||
copy_files "$@"
|
||||
elif [ "$1" == "restart" ]; then
|
||||
shift 2
|
||||
restart_container $container $@
|
||||
elif [ "$1" == "stop" ]; then
|
||||
shift 2
|
||||
stop_container $container $@
|
||||
elif [ "$1" == "revert" ]; then
|
||||
shift 2
|
||||
revert_container $container $@
|
||||
elif [ "$1" == "shell" ]; then
|
||||
shift 2
|
||||
shell_container $container "$@"
|
||||
elif [ "$1" == "upgrade" ]; then
|
||||
shift 2
|
||||
upgrade_container $container $@
|
||||
elif [ "$1" == "restore" ]; then
|
||||
shift
|
||||
restore "$@"
|
||||
elif [ "$1" == "backup" ]; then
|
||||
shift
|
||||
backup "$@"
|
||||
elif [ "$1" == "destroy" ]; then
|
||||
shift 2
|
||||
destroy_container $container $@
|
||||
elif [ "$1" == "logs" ]; then
|
||||
logs $container
|
||||
elif [ "$1" == "post_start_hooks" ]; then
|
||||
shift 2
|
||||
post_start_hooks "$container" "$@"
|
||||
else
|
||||
echo "Invalid selection."
|
||||
show_usage
|
||||
fi
|
2
files/fuel-docker-utils/dockerctl-alias.sh
Normal file
2
files/fuel-docker-utils/dockerctl-alias.sh
Normal file
@ -0,0 +1,2 @@
|
||||
alias cobbler='dockerctl shell cobbler cobbler'
|
||||
alias mco='dockerctl shell astute mco'
|
132
files/fuel-docker-utils/dockerctl_config
Normal file
132
files/fuel-docker-utils/dockerctl_config
Normal file
@ -0,0 +1,132 @@
|
||||
#!/bin/bash
|
||||
|
||||
### Container information
|
||||
#Paths
|
||||
DOCKER_ROOT="/var/www/nailgun/docker"
|
||||
IMAGE_DIR="${DOCKER_ROOT}/images"
|
||||
SOURCE_DIR="${DOCKER_ROOT}/sources"
|
||||
#SUPERVISOR_CONF_DIR="${docker_root}/supervisor.d"
|
||||
#SUPERVISOR_CONF_DIR="${docker_root}/supervisor"
|
||||
#SUPERVISOR_CONF_DIR="<%= @config_dir %>/supervisor/"
|
||||
ASTUTE_YAML="/etc/fuel/astute.yaml"
|
||||
DOCKER_ENGINE="native"
|
||||
ADMIN_IP="10.20.0.2"
|
||||
LOCAL_IP="127.0.0.1"
|
||||
|
||||
#Version of Fuel to deploy
|
||||
VERSION=$(awk '/release/{gsub(/"/, "");print $2}' /etc/fuel/version.yaml || echo <%= @release %>)
|
||||
IMAGE_PREFIX="fuel"
|
||||
# busybox image for storage containers
|
||||
BUSYBOX_IMAGE="busybox.tar.gz"
|
||||
# base centos image for all containers
|
||||
BASE_IMAGE="centos.tar.gz"
|
||||
# Order in which to start all containers
|
||||
CONTAINER_SEQUENCE="postgres rabbitmq keystone rsync astute rsyslog nailgun ostf nginx cobbler mcollective"
|
||||
|
||||
# storage container names
|
||||
PREFIX_STORAGE="fuel-core-${VERSION}-volume-"
|
||||
|
||||
# app container names
|
||||
declare -A CONTAINER_NAMES
|
||||
prefix="fuel-core-${VERSION}-"
|
||||
CONTAINER_NAMES['cobbler']="${prefix}cobbler"
|
||||
CONTAINER_NAMES['postgres']="${prefix}postgres"
|
||||
CONTAINER_NAMES['rabbitmq']="${prefix}rabbitmq"
|
||||
CONTAINER_NAMES['rsync']="${prefix}rsync"
|
||||
CONTAINER_NAMES['astute']="${prefix}astute"
|
||||
CONTAINER_NAMES['nailgun']="${prefix}nailgun"
|
||||
CONTAINER_NAMES['ostf']="${prefix}ostf"
|
||||
CONTAINER_NAMES['nginx']="${prefix}nginx"
|
||||
CONTAINER_NAMES['rsyslog']="${prefix}rsyslog"
|
||||
CONTAINER_NAMES['mcollective']="${prefix}mcollective"
|
||||
CONTAINER_NAMES['keystone']="${prefix}keystone"
|
||||
|
||||
# app container options
|
||||
declare -A CONTAINER_OPTIONS
|
||||
base_opts="-t --net=host"
|
||||
FOREGROUND="-i"
|
||||
BACKGROUND="-d"
|
||||
BIND_ALL=""
|
||||
BIND_ADMIN="${ADMIN_IP}:"
|
||||
BIND_LOCAL="${LOCAL_IP}:"
|
||||
CONTAINER_OPTIONS["cobbler"]="-p ${BIND_ALL}53:53/udp -p ${BIND_ALL}69:69/udp -p ${BIND_ALL}80:80 -p ${BIND_ALL}443:443 --privileged $base_opts"
|
||||
CONTAINER_OPTIONS["postgres"]="-p ${BIND_ADMIN}5432:5432 -p ${BIND_LOCAL}5432:5432 $base_opts"
|
||||
CONTAINER_OPTIONS["rabbitmq"]="-p ${BIND_ADMIN}5672:5672 -p ${BIND_LOCAL}5672:5672 -p ${BIND_ADMIN}4369:4369 -p ${BIND_LOCAL}4369:4369 -p ${BIND_ADMIN}15672:15672 -p ${BIND_LOCAL}15672:15672 -p ${BIND_ADMIN}61613:61613 -p ${BIND_LOCAL}61613:61613 $base_opts"
|
||||
CONTAINER_OPTIONS["rsync"]="-p ${BIND_ADMIN}873:873 -p ${BIND_LOCAL}873:873 $base_opts"
|
||||
CONTAINER_OPTIONS["astute"]="$base_opts"
|
||||
CONTAINER_OPTIONS["nailgun"]="--privileged -p ${BIND_ADMIN}8001:8001 -p ${BIND_LOCAL}8001:8001 $base_opts"
|
||||
CONTAINER_OPTIONS["ostf"]="-p ${BIND_ADMIN}8777:8777 -p ${BIND_LOCAL}8777:8777 $base_opts"
|
||||
CONTAINER_OPTIONS["nginx"]="-p ${BIND_ALL}8000:8000 -p ${BIND_ALL}8080:8080 $base_opts"
|
||||
CONTAINER_OPTIONS["rsyslog"]="--privileged -p ${BIND_ADMIN}514:514 -p ${BIND_LOCAL}514:514 -p ${BIND_ADMIN}514:514/udp -p ${BIND_LOCAL}514:514/udp -p ${BIND_ADMIN}25150:25150 -p ${BIND_LOCAL}25150:25150 $base_opts"
|
||||
CONTAINER_OPTIONS["mcollective"]="--privileged $base_opts"
|
||||
CONTAINER_OPTIONS["keystone"]="-p ${BIND_ALL}5000:5000 -p ${BIND_ALL}35357:35357 $base_opts"
|
||||
|
||||
######
|
||||
#Dependency of volumes for deployment
|
||||
#####
|
||||
|
||||
#Host volumes
|
||||
declare -A HOST_VOL
|
||||
HOST_VOL['repo']="-v /var/www/nailgun:/var/www/nailgun:rw -v /etc/yum.repos.d:/etc/yum.repos.d:rw"
|
||||
HOST_VOL['puppet']="-v /etc/puppet:/etc/puppet:ro"
|
||||
HOST_VOL['sshkey']="-v /root/.ssh:/root/.ssh:ro"
|
||||
HOST_VOL['astuteyaml']="-v /etc/fuel:/etc/fuel:ro"
|
||||
HOST_VOL['logs']="-v /var/log/docker-logs:/var/log"
|
||||
HOST_VOL['keys']="-v /var/lib/fuel/keys:/var/lib/fuel/keys:rw"
|
||||
|
||||
#Persistent directories for container data
|
||||
HOST_VOL['astute_data']="-v /var/lib/fuel/container_data/$VERSION/astute:/var/lib/astute"
|
||||
HOST_VOL['cobbler_data']="-v /var/lib/fuel/container_data/$VERSION/cobbler:/var/lib/cobbler"
|
||||
HOST_VOL['postgres_data']="-v /var/lib/fuel/container_data/$VERSION/postgres:/var/lib/pgsql"
|
||||
|
||||
#Storage container volume mounts
|
||||
declare -A CONTAINER_VOLUMES
|
||||
#Format: CONTAINER_VOLUMES[$FOO_CNT]="${HOST_VOL['foo']}"
|
||||
|
||||
#Storage container volumes
|
||||
#Format: FOO_VOL="--volumes-from $FOO_CNT"
|
||||
|
||||
#Nailgun static files are in nailgun container
|
||||
NAILGUN_VOL="--volumes-from ${CONTAINER_NAMES['nailgun']}"
|
||||
COBBLER_VOL="--volumes-from ${CONTAINER_NAMES['cobbler']}"
|
||||
ASTUTE_VOL="--volumes-from ${CONTAINER_NAMES['astute']}"
|
||||
|
||||
#App container volume mounts
|
||||
###requirements cheat sheet
|
||||
###ALL: astuteyaml repo logs
|
||||
###puppet: rsync
|
||||
###sshkey: nailgun cobbler astute mcollective ostf
|
||||
###repo: nginx mcollective
|
||||
###nailgun: nginx
|
||||
###cobbler: mcollective
|
||||
###astute: mcollective
|
||||
declare -A REQS
|
||||
REQS["${HOST_VOL['astuteyaml']}"]="cobbler postgres rabbitmq rsync astute nailgun ostf nginx rsyslog mcollective keystone"
|
||||
REQS["${HOST_VOL['keys']}"]="mcollective astute"
|
||||
REQS["${HOST_VOL['repo']}"]="cobbler postgres rabbitmq rsync astute nailgun ostf nginx rsyslog mcollective keystone"
|
||||
REQS["${HOST_VOL['logs']}"]="cobbler postgres rabbitmq rsync astute nailgun ostf nginx rsyslog mcollective keystone"
|
||||
#Most containers work from local integrated puppet, but rsync needs to serve host puppet
|
||||
REQS["${HOST_VOL['puppet']}"]="rsync"
|
||||
#Uncomment to enable host puppet manifests
|
||||
#REQS["${HOST_VOL['puppet']}"]="cobbler postgres rabbitmq rsync astute nailgun ostf nginx rsyslog mcollective keystone"
|
||||
REQS["${HOST_VOL['astute_data']}"]="astute"
|
||||
REQS["${HOST_VOL['cobbler_data']}"]="cobbler"
|
||||
REQS["${HOST_VOL['postgres_data']}"]="postgres"
|
||||
REQS["${HOST_VOL['sshkey']}"]="nailgun cobbler astute mcollective ostf"
|
||||
REQS["$NAILGUN_VOL"]="nginx"
|
||||
REQS["$COBBLER_VOL"]="mcollective"
|
||||
REQS["$ASTUTE_VOL"]="mcollective"
|
||||
|
||||
#assemble requirements
|
||||
for requirement in "${!REQS[@]}"; do
|
||||
for container in ${REQS["$requirement"]}; do
|
||||
CONTAINER_VOLUMES["$container"]+="${requirement} "
|
||||
done
|
||||
done
|
||||
|
||||
#backup settings
|
||||
SYSTEM_DIRS="/etc/puppet /etc/fuel /var/lib/fuel /var/www/nailgun /root/.ssh"
|
||||
BACKUP_ROOT="/var/backup/fuel"
|
||||
|
||||
# number of retries for "docker check"
|
||||
CHECK_RETRIES=240
|
695
files/fuel-docker-utils/functions.sh
Normal file
695
files/fuel-docker-utils/functions.sh
Normal file
@ -0,0 +1,695 @@
|
||||
#!/bin/bash
|
||||
# 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.
|
||||
|
||||
if ${DEBUG}; then
|
||||
DOCKER="docker -D"
|
||||
else
|
||||
DOCKER="docker"
|
||||
fi
|
||||
|
||||
function show_usage {
|
||||
echo "Usage:"
|
||||
echo " $0 command"
|
||||
echo
|
||||
echo "Available commands: (Note: work in progress)"
|
||||
echo " help: show this message"
|
||||
echo " build: create all Docker containers"
|
||||
echo " list: list container short names (-l for more output)"
|
||||
echo " start: start all Docker containers"
|
||||
echo " restart: restart one or more Docker containers"
|
||||
echo " stop: stop one or more Docker containers"
|
||||
echo " shell: start a shell or run a command in a Docker container"
|
||||
echo " logs: print console log from a container"
|
||||
echo " revert: reset container to original state"
|
||||
echo " destroy: destroy one or more containers"
|
||||
echo " copy: copy files in or out of container"
|
||||
echo " check: check of container is ready"
|
||||
echo " backup: back up entire deployment"
|
||||
echo " restore: restore backed up deployment"
|
||||
}
|
||||
|
||||
function parse_options {
|
||||
opts="$@"
|
||||
for opt in $@; do
|
||||
case $opt in
|
||||
-V|--version) VERSION=$2
|
||||
shift 2
|
||||
;;
|
||||
-d|--debug) DEBUG=true
|
||||
shift
|
||||
;;
|
||||
--nodebug) DEBUG=false
|
||||
shift
|
||||
;;
|
||||
--) shift
|
||||
nonopts+=("$@")
|
||||
return
|
||||
;;
|
||||
help|build|start|check|list|copy|restart|stop|revert|shell|upgrade|restore|backup|destroy|logs|post_start_hooks)
|
||||
nonopts+=("$@")
|
||||
return
|
||||
;;
|
||||
-*) echo "Unrecognized option: $opt" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
*) nonopts+=("$opt")
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
function debug {
|
||||
if $DEBUG; then
|
||||
echo $@
|
||||
fi
|
||||
}
|
||||
function build_image {
|
||||
${DOCKER} build -t $2 $1
|
||||
}
|
||||
|
||||
function revert_container {
|
||||
stop_container $1
|
||||
destroy_container $1
|
||||
start_container $1
|
||||
}
|
||||
|
||||
function build_storage_containers {
|
||||
#Format: build_image $SOURCE_DIR/storage-foo storage/foo
|
||||
return 0
|
||||
}
|
||||
|
||||
function retry_checker {
|
||||
tries=0
|
||||
echo "checking with command \"$*\""
|
||||
until eval $*; do
|
||||
rc=$?
|
||||
((tries++))
|
||||
echo "try number $tries"
|
||||
echo "return code is $rc"
|
||||
if [ $tries -gt $CHECK_RETRIES ];then
|
||||
failure=1
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
function get_service_credentials {
|
||||
credentialfile=$(mktemp /tmp/servicepws.XXXXX)
|
||||
get_service_credentials.py $ASTUTE_YAML > $credentialfile
|
||||
. $credentialfile
|
||||
rm -f $credentialfile
|
||||
}
|
||||
|
||||
function check_ready {
|
||||
#Uses a custom command to ensure a container is ready
|
||||
get_service_credentials
|
||||
failure=0
|
||||
echo "checking container $1"
|
||||
|
||||
case $1 in
|
||||
nailgun) retry_checker "shell_container nailgun supervisorctl status nailgun | grep -q RUNNING" ;;
|
||||
ostf) retry_checker "egrep -q ^[2-4][0-9]? < <(curl --connect-timeout 1 -s -w '%{http_code}' http://$ADMIN_IP:8777/ostf/not_found -o /dev/null)" ;;
|
||||
#NOTICE: Cobbler console tool does not comply unix conversation: 'cobbler profile find' always return 0 as exit code
|
||||
cobbler) retry_checker "shell_container cobbler ps waux | grep -q 'cobblerd -F' && pgrep dnsmasq"
|
||||
retry_checker "shell_container cobbler cobbler profile find --name=centos* | grep -q centos && shell_container cobbler cobbler profile find --name=ubuntu* | grep -q ubuntu && shell_container cobbler cobbler profile find --name=bootstrap* | grep -q bootstrap" ;;
|
||||
rabbitmq) retry_checker "curl -f -L -i -u \"$astute_user:$astute_password\" http://$ADMIN_IP:15672/api/nodes 1>/dev/null 2>&1"
|
||||
retry_checker "curl -f -L -u \"$mcollective_user:$mcollective_password\" -s http://$ADMIN_IP:15672/api/exchanges | grep -qw 'mcollective_broadcast'"
|
||||
retry_checker "curl -f -L -u \"$mcollective_user:$mcollective_password\" -s http://$ADMIN_IP:15672/api/exchanges | grep -qw 'mcollective_directed'" ;;
|
||||
postgres) retry_checker "shell_container postgres PGPASSWORD=$postgres_nailgun_password /usr/bin/psql -h $ADMIN_IP -U \"$postgres_nailgun_user\" \"$postgres_nailgun_dbname\" -c '\copyright' 2>&1 1>/dev/null" ;;
|
||||
astute) retry_checker "shell_container astute ps waux | grep -q 'astuted'"
|
||||
retry_checker "curl -f -L -u \"$astute_user:$astute_password\" -s http://$ADMIN_IP:15672/api/exchanges | grep -qw 'nailgun'"
|
||||
retry_checker "curl -f -L -u \"$astute_user:$astute_password\" -s http://$ADMIN_IP:15672/api/exchanges | grep -qw 'naily_service'" ;;
|
||||
rsync) retry_checker "shell_container rsync netstat -ntl | grep -q 873" ;;
|
||||
rsyslog) retry_checker "shell_container rsyslog netstat -nl | grep -q 514" ;;
|
||||
mcollective) retry_checker "shell_container mcollective ps waux | grep -q mcollectived" ;;
|
||||
nginx) retry_checker "shell_container nginx ps waux | grep -q nginx" ;;
|
||||
keystone) retry_checker "shell_container keystone keystone --os-auth-url \"http://$ADMIN_IP:35357/v2.0\" --os-username \"$keystone_nailgun_user\" --os-password \"$keystone_nailgun_password\" token-get &>/dev/null" ;;
|
||||
*) echo "No defined test for determining if $1 is ready."
|
||||
;;
|
||||
esac
|
||||
|
||||
#Catch all to ensure puppet is not running
|
||||
retry_checker "! shell_container $1 pgrep puppet"
|
||||
|
||||
if [ $failure -eq 1 ]; then
|
||||
echo "ERROR: $1 failed to start."
|
||||
return 1
|
||||
else
|
||||
echo "$1 is ready."
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function run_storage_containers {
|
||||
#Run storage containers once
|
||||
#Note: storage containers exit, but keep volumes available
|
||||
#Example:
|
||||
#${DOCKER} run -d ${CONTAINER_VOLUMES[$FOO_CNT]} --name "$FOO_CNT" storage/foo || true
|
||||
return 0
|
||||
}
|
||||
|
||||
function export_containers {
|
||||
#--trim option removes $CNT_PREFIX from container name when exporting
|
||||
if [[ "$1" == "--trim" ]]; then
|
||||
trim=true
|
||||
shift
|
||||
else
|
||||
trim=false
|
||||
fi
|
||||
|
||||
for image in $@; do
|
||||
[ $trim ] && image=$(sed "s/${CNT_PREFIX}//" <<< "$image")
|
||||
${DOCKER} export $1 | gzip -c > "${image}.tar.gz"
|
||||
done
|
||||
}
|
||||
function list_containers {
|
||||
#Usage:
|
||||
# (no option) short names
|
||||
# -l (short and long names and status)
|
||||
if [[ "$1" = "-l" ]]; then
|
||||
printf "%-13s%-25s%-13s%-25s\n" "Name" "Image" "Status" "Full container name"
|
||||
for container in "${!CONTAINER_NAMES[@]}"; do
|
||||
if container_created $container; then
|
||||
if is_running $container; then
|
||||
running="Running"
|
||||
else
|
||||
running="Stopped"
|
||||
fi
|
||||
else
|
||||
running="Not created"
|
||||
fi
|
||||
longname="${CONTAINER_NAMES["$container"]}"
|
||||
imagename="${IMAGE_PREFIX}/${container}_${VERSION}"
|
||||
printf "%-13s%-25s%-13s%-25s\n" "$container" "$imagename" "$running" "$longname"
|
||||
done
|
||||
else
|
||||
for container in "${!CONTAINER_NAMES[@]}"; do
|
||||
echo $container
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
function commit_container {
|
||||
container_name="${CONTAINER_NAMES[$1]}"
|
||||
image="$IMAGE_PREFIX/$1_$VERSION"
|
||||
${DOCKER} commit $container_name $image
|
||||
}
|
||||
function start_container {
|
||||
if [ -z "$1" ]; then
|
||||
echo "Must specify a container name" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$1" = "all" ]; then
|
||||
for container in $CONTAINER_SEQUENCE; do
|
||||
start_container $container
|
||||
done
|
||||
return
|
||||
fi
|
||||
image_name="$IMAGE_PREFIX/$1"
|
||||
container_name=${CONTAINER_NAMES[$1]}
|
||||
if container_created "$container_name"; then
|
||||
pre_start_hooks $1
|
||||
if is_running "$container_name"; then
|
||||
if is_ghost "$container_name"; then
|
||||
restart_container $1
|
||||
else
|
||||
echo "$container_name is already running."
|
||||
fi
|
||||
else
|
||||
# Clean up broken mounts if needed
|
||||
id=$(get_container_id $container_name)
|
||||
umount -l $(grep "$id" /proc/mounts | awk '{print $2}' | sort -r) 2>/dev/null
|
||||
${DOCKER} start $container_name
|
||||
fi
|
||||
post_start_hooks $1
|
||||
if [ "$2" = "--attach" ]; then
|
||||
attach_container $container_name
|
||||
fi
|
||||
else
|
||||
first_run_container "$1" $2
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
function shutdown_container {
|
||||
echo "Stopping $1..."
|
||||
kill $2
|
||||
${DOCKER} stop $1
|
||||
exit 0
|
||||
}
|
||||
|
||||
function attach_container {
|
||||
echo "Attaching to container $1..."
|
||||
${DOCKER} attach --no-stdin $1 &
|
||||
APID=$!
|
||||
trap "shutdown_container $1 $APID" INT TERM
|
||||
while test -d "/proc/$APID/fd" ; do
|
||||
sleep 10 & wait $!
|
||||
done
|
||||
}
|
||||
|
||||
function shell_container {
|
||||
case $EXEC_DRIVER in
|
||||
lxc) lxc_shell_container "$@"
|
||||
;;
|
||||
*) exec_shell_container "$@"
|
||||
esac
|
||||
}
|
||||
|
||||
function exec_shell_container {
|
||||
exec_opts=''
|
||||
#Interactive shell only if we have TTY
|
||||
if [ -t 0 ]; then
|
||||
exec_opts+=' -i'
|
||||
else
|
||||
#FIXME(mattymo): BASH 3.1.3 and higher don't need sleep
|
||||
sleep 0.1
|
||||
if read -t 0; then
|
||||
exec_opts+=' -i'
|
||||
fi
|
||||
fi
|
||||
if [ -t 1 -a ! -p /proc/self/fd/0 ]; then
|
||||
exec_opts+=' -t'
|
||||
fi
|
||||
id=$(get_container_id "$1")
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Could not get docker ID for $container. Is it running?" 1>&2
|
||||
return 1
|
||||
fi
|
||||
#TODO(mattymo): fix UTF-8 bash warning
|
||||
#Setting C locale to suppress bash warning
|
||||
prefix="env LANG=C"
|
||||
if [ -z "$2" ]; then
|
||||
command="/bin/bash"
|
||||
else
|
||||
shift
|
||||
command=("$@")
|
||||
fi
|
||||
docker exec $exec_opts $id $prefix "${command[@]}"
|
||||
}
|
||||
|
||||
function lxc_shell_container {
|
||||
id=$(get_container_id "$1")
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Could not get docker ID for $container. Is it running?" 1>&2
|
||||
return 1
|
||||
fi
|
||||
if [ -z "$2" ]; then
|
||||
command="/bin/bash"
|
||||
else
|
||||
shift
|
||||
command=("$@")
|
||||
fi
|
||||
lxc-attach --name "$id" -- "${command[@]}"
|
||||
}
|
||||
|
||||
function stop_container {
|
||||
if [[ "$1" == 'all' ]]; then
|
||||
${DOCKER} stop ${CONTAINER_NAMES[@]}
|
||||
else
|
||||
for container in $@; do
|
||||
echo "Stopping $container..."
|
||||
${DOCKER} stop ${CONTAINER_NAMES[$container]}
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
function destroy_container {
|
||||
if [[ "$1" == 'all' ]]; then
|
||||
stop_container all
|
||||
${DOCKER} rm -f ${CONTAINER_NAMES[@]}
|
||||
else
|
||||
for container in $@; do
|
||||
stop_container $container
|
||||
${DOCKER} rm -f ${CONTAINER_NAMES[$container]}
|
||||
if [ $? -ne 0 ]; then
|
||||
#This happens because devicemapper glitched
|
||||
#Try to unmount all devicemapper mounts manually and try again
|
||||
echo "Destruction of container $container failed. Trying workaround..."
|
||||
id=$(${DOCKER} inspect -f='{{if .ID}}{{.ID}}{{else}}{{.Id}}{{end}}' ${CONTAINER_NAMES[$container]})
|
||||
if [ -z $id ]; then
|
||||
echo "Could not get docker ID for $container" 1>&2
|
||||
return 1
|
||||
fi
|
||||
umount -l $(grep "$id" /proc/mounts | awk '{print $2}' | sort -r)
|
||||
#Try to delete again
|
||||
${DOCKER} rm -f ${CONTAINER_NAMES[$container]}
|
||||
if [ $? -ne 0 ];then
|
||||
echo "Workaround failed. Unable to destroy container $container."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
function logs {
|
||||
${DOCKER} logs ${CONTAINER_NAMES[$1]}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function restart_container {
|
||||
${DOCKER} restart ${CONTAINER_NAMES[$1]}
|
||||
}
|
||||
|
||||
function container_lookup {
|
||||
echo ${CONTAINER_NAMES[$1]}
|
||||
}
|
||||
|
||||
function get_container_id {
|
||||
#Try to get ID from container short name first
|
||||
id=$(${DOCKER} inspect -f='{{if .ID}}{{.ID}}{{else}}{{.Id}}{{end}}' ${CONTAINER_NAMES[$1]} 2>/dev/null)
|
||||
if [ -z "$id" ]; then
|
||||
#Try to get ID short ID, long ID, or container name
|
||||
id=$(${DOCKER} inspect -f='{{if .ID}}{{.ID}}{{else}}{{.Id}}{{end}}' "$1")
|
||||
if [ -z "$id" ]; then
|
||||
echo "Could not get docker ID for container $1. Is it running?" 1>&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
echo "$id"
|
||||
}
|
||||
function container_created {
|
||||
${DOCKER} ps -a | grep -q $1
|
||||
return $?
|
||||
}
|
||||
function is_ghost {
|
||||
LANG=C ${DOCKER} ps | grep $1 | grep -q Ghost
|
||||
return $?
|
||||
}
|
||||
function is_running {
|
||||
${DOCKER} ps | grep -q $1
|
||||
return $?
|
||||
}
|
||||
function first_run_container {
|
||||
|
||||
opts="${CONTAINER_OPTIONS[$1]} ${CONTAINER_VOLUMES[$1]}"
|
||||
container_name="${CONTAINER_NAMES[$1]}"
|
||||
image="$IMAGE_PREFIX/$1_$VERSION"
|
||||
if ! is_running $container_name; then
|
||||
pre_setup_hooks $1
|
||||
${DOCKER} run $opts $BACKGROUND --name=$container_name $image
|
||||
post_setup_hooks $1
|
||||
else
|
||||
echo "$container_name is already running."
|
||||
fi
|
||||
if [ "$2" = "--attach" ]; then
|
||||
attach_container $container_name
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function pre_setup_hooks {
|
||||
return 0
|
||||
}
|
||||
|
||||
function pre_start_hooks {
|
||||
return 0
|
||||
}
|
||||
|
||||
function post_setup_hooks {
|
||||
case $1 in
|
||||
*) ;;
|
||||
esac
|
||||
}
|
||||
function post_start_hooks {
|
||||
case $1 in
|
||||
*) ;;
|
||||
esac
|
||||
}
|
||||
|
||||
function container_root {
|
||||
id=$(${DOCKER} inspect -f='{{if .ID}}{{.ID}}{{else}}{{.Id}}{{end}}' ${CONTAINER_NAMES[$1]})
|
||||
if [ -n "$id" ]; then
|
||||
echo "/var/lib/docker/devicemapper/mnt/${id}/rootfs"
|
||||
return 0
|
||||
else
|
||||
echo "Unable to get root for container ${1}." 1>&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function copy_files {
|
||||
#Overview:
|
||||
# Works similar to rsync:
|
||||
# Container to host:
|
||||
# sync_files cobbler:/var/lib/tftpboot/ /localpath/
|
||||
# Host to container:
|
||||
# sync_files /etc/puppet cobbler:/etc/puppet
|
||||
#TODO(mattymo): add options and more parameters
|
||||
|
||||
if [ -z "$2" ]; then
|
||||
echo "This command requires two parameters. See usage:"
|
||||
echo " $0 copy src dest"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo " $0 copy nailgun:/etc/nailguns/settings.yaml /root/settings.yaml"
|
||||
echo " $0 copy /root/newpkg.rpm mcollective:/root/"
|
||||
exit 1
|
||||
fi
|
||||
#Test which parameter is local
|
||||
if test -n "$(shopt -s nullglob; echo $1*)"; then
|
||||
method="push"
|
||||
local=$1
|
||||
remote=$2
|
||||
else
|
||||
method="pull"
|
||||
remote=$1
|
||||
local=$2
|
||||
fi
|
||||
container=$(echo $remote | cut -d':' -f1)
|
||||
remotepath=$(echo $remote | cut -d':' -f2-)
|
||||
if [[ ${CONTAINER_NAMES[@]} =~ .*${container}.* ]]; then
|
||||
cont_root=$(container_root $container)
|
||||
if [ $? -ne 0 ];then return 1; fi
|
||||
else
|
||||
echo "Unable to locate container to copy to/from."
|
||||
return 2
|
||||
fi
|
||||
remote="${cont_root}/${remotepath}"
|
||||
if [ "$method" = "push" ]; then
|
||||
cp -R $local $remote
|
||||
else
|
||||
cp -R $remote $local
|
||||
fi
|
||||
}
|
||||
|
||||
function backup {
|
||||
backup_id=$(date +%F_%H%S)
|
||||
use_rsync=0
|
||||
#Sets backup_dir
|
||||
parse_backup_dir $1
|
||||
[[ "$backup_dir" =~ var ]] && verify_disk_space "backup"
|
||||
if check_nailgun_tasks; then
|
||||
echo "There are currently running Fuel tasks. Please wait for them to \
|
||||
finish or cancel them." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
backup_containers "$backup_id"
|
||||
backup_system_dirs
|
||||
backup_compress
|
||||
[ $use_rsync -eq 1 ] && backup_rsync_upload $rsync_dest $backup_dir
|
||||
backup_cleanup $backup_dir
|
||||
echo "Backup complete. File is available at $backup_dir/fuel_backup${image_suffix}.tar.lrz"
|
||||
}
|
||||
|
||||
function parse_backup_dir {
|
||||
use_rsync=0
|
||||
if [ -z "$1" ]; then
|
||||
#Default backup dir
|
||||
backup_dir="${BACKUP_ROOT}/backup_${backup_id}"
|
||||
elif [ -d "$1" ]; then
|
||||
#User defined dir exists, so use it
|
||||
backup_dir="$1"
|
||||
elif [[ "$1" =~ .:. ]]; then
|
||||
#Remote rsync dir
|
||||
use_rsync=1
|
||||
backup_dir="${BACKUP_ROOT}/backup_${backup_id}"
|
||||
rsync_dest="$1"
|
||||
else
|
||||
echo "Unrecognized backup destination. Valid options include:" 1>&2
|
||||
echo " (blank) - backup to $BACKUP_ROOT" 1>&2
|
||||
echo " /path/to/backup - local backup directory" 1>&2
|
||||
echo " user@server:/path - backup using rsync to server" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function backup_containers {
|
||||
#Backs up all containers, regardless of being related to Fuel
|
||||
|
||||
image_suffix="_$1"
|
||||
purge_images=0
|
||||
|
||||
[ $purge_images -eq 0 ] && rm -rf "$backup_dir"
|
||||
mkdir -p $SYSTEM_DIRS $backup_dir
|
||||
echo "Reading container data..."
|
||||
while read containerid; do
|
||||
container_name="$(${DOCKER} inspect -f='{{.Name}}' $containerid | tr -d '/')"
|
||||
container_image="$(${DOCKER} inspect -f='{{.Config.Image}}' $containerid)"
|
||||
container_image+=$image_suffix
|
||||
container_archive="$(echo "$container_image" | sed 's/\//__/').tar"
|
||||
#Commit container as new image
|
||||
echo "Committing $container_name..."
|
||||
${DOCKER} commit "$containerid" "${container_image}"
|
||||
echo "Saving $container_name..."
|
||||
${DOCKER} save "${container_image}" > "${backup_dir}/${container_archive}"
|
||||
echo "Cleaning up temporary image..."
|
||||
${DOCKER} rmi "${container_image}"
|
||||
done < <(${DOCKER} ps -aq)
|
||||
}
|
||||
|
||||
function backup_system_dirs {
|
||||
echo "Archiving system folders"
|
||||
tar cf $backup_dir/system-dirs.tar -C / $SYSTEM_DIRS
|
||||
}
|
||||
|
||||
function backup_compress {
|
||||
echo "Compressing archives..."
|
||||
component_tars=($backup_dir/*.tar)
|
||||
( cd $backup_dir && tar cf $backup_dir/fuel_backup${image_suffix}.tar *.tar )
|
||||
rm -rf "${component_tars[@]}"
|
||||
#Improve compression on bare metal
|
||||
if [ -z "$(virt-what)" ] ; then
|
||||
lrzopts="-L2 -U"
|
||||
else
|
||||
lrzopts="-L2"
|
||||
fi
|
||||
lrzip $lrzopts "$backup_dir/fuel_backup${image_suffix}.tar" -o "$backup_dir/fuel_backup${image_suffix}.tar.lrz"
|
||||
|
||||
}
|
||||
|
||||
function backup_rsync_upload {
|
||||
dest="$1"
|
||||
backup_dir="$2"
|
||||
echo "Starting rsync backup. You may be prompted for a login."
|
||||
rsync -vP $backup_dir/*.tar.lrz "$dest"
|
||||
}
|
||||
|
||||
function backup_cleanup {
|
||||
echo "Cleaning up..."
|
||||
[ -d "$1" ] && rm -f $1/*.tar
|
||||
}
|
||||
|
||||
function check_nailgun_tasks {
|
||||
#Returns 0 if tasks are running in nailgun
|
||||
#if command returns error, then app is not running
|
||||
shell_container nailgun fuel task &> /dev/null || return 1
|
||||
shell_container nailgun fuel task | grep -q running &> /dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
function restore {
|
||||
#TODO(mattymo): Optionally not include system dirs during restore
|
||||
#TODO(mattymo): support remote file such as ssh://user@myhost/backup.tar.lrz
|
||||
# or http://myhost/backup.tar.lrz
|
||||
if check_nailgun_tasks; then
|
||||
echo "There are currently running Fuel tasks. Please wait for them to \
|
||||
finish or cancel them. Run \"fuel task list\" for more details." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
verify_disk_space "restore"
|
||||
backupfile=$1
|
||||
if [ -z "$backupfile" ]; then
|
||||
#TODO(mattymo): Parse BACKUP_DIR for lrz files
|
||||
echo "Specify a backup file to restore" 1>&2
|
||||
exit 1
|
||||
elif ! [ -f "$backupfile" ]; then
|
||||
echo "Archive does not exist: $backupfile" 1>&2
|
||||
exit 1
|
||||
elif ! [[ "$backupfile" =~ lrz$ ]]; then
|
||||
echo "Archive does not have lrz extension." 1>&2
|
||||
exit 2
|
||||
fi
|
||||
timestamp=$(echo $backupfile | sed -n 's/.*\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9][0-9][0-9]\).*/\1/p')
|
||||
if [ -z "$timestamp" ]; then
|
||||
echo "Unable to parse timestamp in archive." 1>&2
|
||||
exit 3
|
||||
fi
|
||||
restoredir="$BACKUP_ROOT/restore-$timestamp/"
|
||||
disable_supervisor
|
||||
unpack_archive "$backupfile" "$restoredir"
|
||||
restore_images "$restoredir"
|
||||
rename_images "$timestamp"
|
||||
restore_systemdirs "$restoredir"
|
||||
echo "Stopping and destroying existing containers..."
|
||||
destroy_container all
|
||||
echo "Preparing storage containers..."
|
||||
run_storage_containers
|
||||
echo "Starting application containers..."
|
||||
start_container all
|
||||
enable_supervisor
|
||||
for container in $CONTAINER_SEQUENCE; do
|
||||
check_ready $container
|
||||
done
|
||||
}
|
||||
|
||||
function unpack_archive {
|
||||
#feedback as everything restores
|
||||
backupfile="$1"
|
||||
restoredir="$2"
|
||||
mkdir -p "$restoredir"
|
||||
lrzip -d -o "$restoredir/fuel_backup.tar" $backupfile
|
||||
tar -xf "$restoredir/fuel_backup.tar" -C "$restoredir" && rm -f "$restoredir/fuel_backup.tar"
|
||||
}
|
||||
|
||||
function restore_images {
|
||||
restoredir="$1"
|
||||
for imgfile in $restoredir/*.tar; do
|
||||
echo "Loading $imgfile..."
|
||||
if ! [[ "$imgfile" =~ system-dirs ]] && ! [[ "$imgfile" =~ fuel_backup.tar ]]; then
|
||||
${DOCKER} load -i $imgfile
|
||||
fi
|
||||
#rm -f $imgfile
|
||||
done
|
||||
}
|
||||
|
||||
function rename_images {
|
||||
timestamp="$1"
|
||||
while read containername; do
|
||||
oldname=$containername
|
||||
newname=$(echo $containername | sed -n "s/_${timestamp}//p")
|
||||
docker tag "$oldname" "$newname"
|
||||
docker rmi "$oldname"
|
||||
done < <(docker images | grep $timestamp | cut -d' ' -f1)
|
||||
}
|
||||
|
||||
function restore_systemdirs {
|
||||
restoredir="$1"
|
||||
tar xf $restoredir/system-dirs.tar -C /
|
||||
}
|
||||
|
||||
function disable_supervisor {
|
||||
supervisorctl shutdown
|
||||
}
|
||||
|
||||
function enable_supervisor {
|
||||
service supervisord start
|
||||
}
|
||||
function verify_disk_space {
|
||||
if [ -z "$1" ]; then
|
||||
echo "Backup or restore operation not specified." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#11gb free space required to backup and restore
|
||||
(( required = 11 * 1024 * 1024 ))
|
||||
avail=$(df /var | grep /var | awk '{print $4}')
|
||||
if (( avail < required )); then
|
||||
echo "Insufficient disk space to perform $1. At least 11gb must be free on /var partition." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
28
files/fuel-docker-utils/get_service_credentials.py
Normal file
28
files/fuel-docker-utils/get_service_credentials.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/python
|
||||
# Copyright 2014 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.
|
||||
|
||||
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
astuteyaml=sys.argv[1]
|
||||
data=yaml.load(open(astuteyaml))
|
||||
for outerkey in data.keys():
|
||||
if isinstance(data[outerkey], dict):
|
||||
for innerkey in data[outerkey].keys():
|
||||
print("%s_%s=\'%s\'" % (outerkey, innerkey, data[outerkey][innerkey]))
|
||||
else:
|
||||
print("%s=\'%s\'" % (outerkey, data[outerkey]))
|
||||
|
351
files/fuel-ha-utils/ocf/ceilometer-agent-central
Normal file
351
files/fuel-ha-utils/ocf/ceilometer-agent-central
Normal file
@ -0,0 +1,351 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
#
|
||||
# OpenStack Ceilometer Central Agent Service (ceilometer-agent-central)
|
||||
#
|
||||
# Description: Manages an OpenStack Ceilometer Central Agent Service (ceilometer-agent-central) process as an HA resource
|
||||
#
|
||||
# Authors: Emilien Macchi
|
||||
# Mainly inspired by the Nova Scheduler resource agent written by Sebastien Han
|
||||
#
|
||||
# Support: openstack@lists.launchpad.net
|
||||
# License: Apache Software License (ASL) 2.0
|
||||
#
|
||||
#
|
||||
# See usage() function below for more details ...
|
||||
#
|
||||
# OCF instance parameters:
|
||||
# OCF_RESKEY_binary
|
||||
# OCF_RESKEY_config
|
||||
# OCF_RESKEY_user
|
||||
# OCF_RESKEY_pid
|
||||
# OCF_RESKEY_monitor_binary
|
||||
# OCF_RESKEY_amqp_server_port
|
||||
# OCF_RESKEY_additional_parameters
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
#######################################################################
|
||||
|
||||
# Fill in some defaults if no values are specified
|
||||
|
||||
OCF_RESKEY_binary_default="ceilometer-agent-central"
|
||||
OCF_RESKEY_config_default="/etc/ceilometer/ceilometer.conf"
|
||||
OCF_RESKEY_user_default="ceilometer"
|
||||
OCF_RESKEY_pid_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
OCF_RESKEY_amqp_server_port_default="5673"
|
||||
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
: ${OCF_RESKEY_amqp_server_port=${OCF_RESKEY_amqp_server_port_default}}
|
||||
|
||||
#######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<UEND
|
||||
usage: $0 (start|stop|validate-all|meta-data|status|monitor)
|
||||
|
||||
$0 manages an OpenStack Ceilometer Central Agent Service (ceilometer-agent-central) process as an HA resource
|
||||
|
||||
The 'start' operation starts the scheduler service.
|
||||
The 'stop' operation stops the scheduler service.
|
||||
The 'validate-all' operation reports whether the parameters are valid
|
||||
The 'meta-data' operation reports this RA's meta-data information
|
||||
The 'status' operation reports whether the scheduler service is running
|
||||
The 'monitor' operation reports whether the scheduler service seems to be working
|
||||
|
||||
UEND
|
||||
}
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="ceilometer-agent-central">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
Resource agent for the OpenStack Ceilometer Central Agent Service (ceilometer-agent-central)
|
||||
May manage a ceilometer-agent-central instance or a clone set that
|
||||
creates a distributed ceilometer-agent-central cluster.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages the OpenStack Ceilometer Central Agent Service (ceilometer-agent-central)</shortdesc>
|
||||
<parameters>
|
||||
|
||||
<parameter name="binary" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack Ceilometer Central Agent server binary (ceilometer-agent-central)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Ceilometer Central Agent server binary (ceilometer-agent-central)</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binary_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack Ceilometer Central Agent Service (ceilometer-agent-central) configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Ceilometer Central Agent (ceilometer-agent-central registry) config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="user" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
User running OpenStack Ceilometer Central Agent Service (ceilometer-agent-central)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Ceilometer Central Agent Service (ceilometer-agent-central) user</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_user_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pid" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The pid file to use for this OpenStack Ceilometer Central Agent Service (ceilometer-agent-central) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Ceilometer Central Agent Service (ceilometer-agent-central) pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pid_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="amqp_server_port" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The listening port number of the AMQP server. Use for monitoring purposes
|
||||
</longdesc>
|
||||
<shortdesc lang="en">AMQP listening port</shortdesc>
|
||||
<content type="integer" default="${OCF_RESKEY_amqp_server_port_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="additional_parameters" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Additional parameters to pass on to the OpenStack Ceilometer Central Agent Service (ceilometer-agent-central)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Additional parameters for ceilometer-agent-central</shortdesc>
|
||||
<content type="string" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20" />
|
||||
<action name="stop" timeout="20" />
|
||||
<action name="status" timeout="20" />
|
||||
<action name="monitor" timeout="30" interval="20" />
|
||||
<action name="validate-all" timeout="5" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Functions invoked by resource manager actions
|
||||
|
||||
ceilometer_agent_central_check_port() {
|
||||
# This function has been taken from the squid RA and improved a bit
|
||||
# The length of the integer must be 4
|
||||
# Examples of valid port: "1080", "0080"
|
||||
# Examples of invalid port: "1080bad", "0", "0000", ""
|
||||
|
||||
local int
|
||||
local cnt
|
||||
|
||||
int="$1"
|
||||
cnt=${#int}
|
||||
echo $int |egrep -qx '[0-9]+(:[0-9]+)?(,[0-9]+(:[0-9]+)?)*'
|
||||
|
||||
if [ $? -ne 0 ] || [ $cnt -ne 4 ]; then
|
||||
ocf_log err "Invalid port number: $1"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
}
|
||||
|
||||
ceilometer_agent_central_validate() {
|
||||
local rc
|
||||
|
||||
check_binary $OCF_RESKEY_binary
|
||||
check_binary netstat
|
||||
ceilometer_agent_central_check_port $OCF_RESKEY_amqp_server_port
|
||||
|
||||
# A config file on shared storage that is not available
|
||||
# during probes is OK.
|
||||
if [ ! -f $OCF_RESKEY_config ]; then
|
||||
if ! ocf_is_probe; then
|
||||
ocf_log err "Config $OCF_RESKEY_config doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
ocf_log_warn "Config $OCF_RESKEY_config not available during a probe"
|
||||
fi
|
||||
|
||||
getent passwd $OCF_RESKEY_user >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "User $OCF_RESKEY_user doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
ceilometer_agent_central_status() {
|
||||
local pid
|
||||
local rc
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${OCF_RESKEY_pid} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
ocf_log debug "Create pid file dir: ${PID_DIR} and chown to ${OCF_RESKEY_user}"
|
||||
mkdir -p "${PID_DIR}"
|
||||
chown -R ${OCF_RESKEY_user} "${PID_DIR}"
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
if [ ! -f $OCF_RESKEY_pid ]; then
|
||||
ocf_log info "OpenStack Ceilometer Central Agent (ceilometer-agent-central) is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
else
|
||||
pid=`cat $OCF_RESKEY_pid`
|
||||
fi
|
||||
|
||||
if [ -n "${pid}" ]; then
|
||||
ocf_run -warn kill -s 0 $pid
|
||||
rc=$?
|
||||
else
|
||||
ocf_log err "PID file ${OCF_RESKEY_pid} is empty!"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
if [ $rc -eq 0 ]; then
|
||||
return $OCF_SUCCESS
|
||||
else
|
||||
ocf_log info "Old PID file found, but OpenStack Ceilometer Central Agent (ceilometer-agent-central) is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
}
|
||||
|
||||
ceilometer_agent_central_monitor() {
|
||||
local rc
|
||||
local pid
|
||||
local scheduler_amqp_check
|
||||
|
||||
ceilometer_agent_central_status
|
||||
rc=$?
|
||||
|
||||
# If status returned anything but success, return that immediately
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
return $rc
|
||||
fi
|
||||
|
||||
ocf_log debug "OpenStack Ceilometer Central Agent (ceilometer-agent-central) monitor succeeded"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
ceilometer_agent_central_start() {
|
||||
local rc
|
||||
|
||||
ceilometer_agent_central_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_SUCCESS ]; then
|
||||
ocf_log info "OpenStack Ceilometer Central Agent (ceilometer-agent-central) already running"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# run the actual ceilometer-agent-central daemon. Don't use ocf_run as we're sending the tool's output
|
||||
# straight to /dev/null anyway and using ocf_run would break stdout-redirection here.
|
||||
su ${OCF_RESKEY_user} -s /bin/sh -c "${OCF_RESKEY_binary} --config-file=$OCF_RESKEY_config \
|
||||
$OCF_RESKEY_additional_parameters"' >> /dev/null 2>&1 & echo $!' > $OCF_RESKEY_pid
|
||||
|
||||
ocf_log debug "Create pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
# Spin waiting for the server to come up.
|
||||
while true; do
|
||||
ceilometer_agent_central_monitor
|
||||
rc=$?
|
||||
[ $rc -eq $OCF_SUCCESS ] && break
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "OpenStack Ceilometer Central Agent (ceilometer-agent-central) start failed"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
ocf_log info "OpenStack Ceilometer Central Agent (ceilometer-agent-central) started"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
ceilometer_agent_central_stop() {
|
||||
local rc
|
||||
local pid
|
||||
|
||||
ceilometer_agent_central_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
ocf_log info "OpenStack Ceilometer Central Agent (ceilometer-agent-central) already stopped"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# Try SIGTERM
|
||||
pid=`cat $OCF_RESKEY_pid`
|
||||
ocf_run kill -s TERM $pid
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "OpenStack Ceilometer Central Agent (ceilometer-agent-central) couldn't be stopped"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
# stop waiting
|
||||
shutdown_timeout=15
|
||||
if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
|
||||
shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5))
|
||||
fi
|
||||
count=0
|
||||
while [ $count -lt $shutdown_timeout ]; do
|
||||
ceilometer_agent_central_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
break
|
||||
fi
|
||||
count=`expr $count + 1`
|
||||
sleep 1
|
||||
ocf_log debug "OpenStack Ceilometer Central Agent (ceilometer-agent-central) still hasn't stopped yet. Waiting ..."
|
||||
done
|
||||
|
||||
ceilometer_agent_central_status
|
||||
rc=$?
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
# SIGTERM didn't help either, try SIGKILL
|
||||
ocf_log info "OpenStack Ceilometer Central Agent (ceilometer-agent-central) failed to stop after ${shutdown_timeout}s \
|
||||
using SIGTERM. Trying SIGKILL ..."
|
||||
ocf_run kill -s KILL $pid
|
||||
fi
|
||||
|
||||
ocf_log info "OpenStack Ceilometer Central Agent (ceilometer-agent-central) stopped"
|
||||
|
||||
ocf_log debug "Delete pid file: ${OCF_RESKEY_pid} with content $(cat $OCF_RESKEY_pid)"
|
||||
rm -f $OCF_RESKEY_pid
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
case "$1" in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS;;
|
||||
usage|help) usage
|
||||
exit $OCF_SUCCESS;;
|
||||
esac
|
||||
|
||||
# Anything except meta-data and help must pass validation
|
||||
ceilometer_agent_central_validate || exit $?
|
||||
|
||||
# What kind of method was invoked?
|
||||
case "$1" in
|
||||
start) ceilometer_agent_central_start;;
|
||||
stop) ceilometer_agent_central_stop;;
|
||||
status) ceilometer_agent_central_status;;
|
||||
monitor) ceilometer_agent_central_monitor;;
|
||||
validate-all) ;;
|
||||
*) usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED;;
|
||||
esac
|
338
files/fuel-ha-utils/ocf/ceilometer-alarm-evaluator
Normal file
338
files/fuel-ha-utils/ocf/ceilometer-alarm-evaluator
Normal file
@ -0,0 +1,338 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
#
|
||||
# OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator)
|
||||
#
|
||||
# Description: Manages an OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator) process as an HA resource
|
||||
#
|
||||
# Authors: Emilien Macchi
|
||||
# Mainly inspired by the Nova Scheduler resource agent written by Sebastien Han
|
||||
#
|
||||
# Support: openstack@lists.launchpad.net
|
||||
# License: Apache Software License (ASL) 2.0
|
||||
#
|
||||
#
|
||||
# See usage() function below for more details ...
|
||||
#
|
||||
# OCF instance parameters:
|
||||
# OCF_RESKEY_binary
|
||||
# OCF_RESKEY_config
|
||||
# OCF_RESKEY_user
|
||||
# OCF_RESKEY_pid
|
||||
# OCF_RESKEY_monitor_binary
|
||||
# OCF_RESKEY_additional_parameters
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
#######################################################################
|
||||
|
||||
# Fill in some defaults if no values are specified
|
||||
|
||||
OCF_RESKEY_binary_default="ceilometer-alarm-evaluator"
|
||||
OCF_RESKEY_config_default="/etc/ceilometer/ceilometer.conf"
|
||||
OCF_RESKEY_user_default="ceilometer"
|
||||
OCF_RESKEY_pid_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
|
||||
#######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<UEND
|
||||
usage: $0 (start|stop|validate-all|meta-data|status|monitor)
|
||||
|
||||
$0 manages an OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator) process as an HA resource
|
||||
|
||||
The 'start' operation starts the service.
|
||||
The 'stop' operation stops the service.
|
||||
The 'validate-all' operation reports whether the parameters are valid
|
||||
The 'meta-data' operation reports this RA's meta-data information
|
||||
The 'status' operation reports whether the service is running
|
||||
The 'monitor' operation reports whether the service seems to be working
|
||||
|
||||
UEND
|
||||
}
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="ceilometer-alarm-evaluator">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
Resource agent for the OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator)
|
||||
May manage a ceilometer-alarm-evaluatorinstance or a clone set that
|
||||
creates a distributed ceilometer-alarm-evaluator cluster.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages the OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator)</shortdesc>
|
||||
<parameters>
|
||||
|
||||
<parameter name="binary" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack Ceilometer Alarm Evaluator server binary (ceilometer-alarm-evaluator)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Ceilometer Alarm Evaluator server binary (ceilometer-alarm-evaluator)</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binary_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator) configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="user" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
User running OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator) user</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_user_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pid" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The pid file to use for this OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator) pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pid_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="additional_parameters" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Additional parameters to pass on to the OpenStack Ceilometer Alarm Evaluator Service (ceilometer-alarm-evaluator)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Additional parameters for ceilometer-alarm-evaluator</shortdesc>
|
||||
<content type="string" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20" />
|
||||
<action name="stop" timeout="20" />
|
||||
<action name="status" timeout="20" />
|
||||
<action name="monitor" timeout="30" interval="20" />
|
||||
<action name="validate-all" timeout="5" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Functions invoked by resource manager actions
|
||||
|
||||
ceilometer_alarm_evaluator_check_port() {
|
||||
# This function has been taken from the squid RA and improved a bit
|
||||
# The length of the integer must be 4
|
||||
# Examples of valid port: "1080", "0080"
|
||||
# Examples of invalid port: "1080bad", "0", "0000", ""
|
||||
|
||||
local int
|
||||
local cnt
|
||||
|
||||
int="$1"
|
||||
cnt=${#int}
|
||||
echo $int |egrep -qx '[0-9]+(:[0-9]+)?(,[0-9]+(:[0-9]+)?)*'
|
||||
|
||||
if [ $? -ne 0 ] || [ $cnt -ne 4 ]; then
|
||||
ocf_log err "Invalid port number: $1"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
}
|
||||
|
||||
ceilometer_alarm_evaluator_validate() {
|
||||
local rc
|
||||
|
||||
check_binary $OCF_RESKEY_binary
|
||||
check_binary netstat
|
||||
|
||||
# A config file on shared storage that is not available
|
||||
# during probes is OK.
|
||||
if [ ! -f $OCF_RESKEY_config ]; then
|
||||
if ! ocf_is_probe; then
|
||||
ocf_log err "Config $OCF_RESKEY_config doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
ocf_log_warn "Config $OCF_RESKEY_config not available during a probe"
|
||||
fi
|
||||
|
||||
getent passwd $OCF_RESKEY_user >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "User $OCF_RESKEY_user doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
ceilometer_alarm_evaluator_status() {
|
||||
local pid
|
||||
local rc
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${OCF_RESKEY_pid} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
ocf_log debug "Create pid file dir: ${PID_DIR} and chown to ${OCF_RESKEY_user}"
|
||||
mkdir -p "${PID_DIR}"
|
||||
chown -R ${OCF_RESKEY_user} "${PID_DIR}"
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
if [ ! -f $OCF_RESKEY_pid ]; then
|
||||
ocf_log info "OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
else
|
||||
pid=`cat $OCF_RESKEY_pid`
|
||||
fi
|
||||
|
||||
if [ -n "${pid}" ]; then
|
||||
ocf_run -warn kill -s 0 $pid
|
||||
rc=$?
|
||||
else
|
||||
ocf_log err "PID file ${OCF_RESKEY_pid} is empty!"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
if [ $rc -eq 0 ]; then
|
||||
return $OCF_SUCCESS
|
||||
else
|
||||
ocf_log info "Old PID file found, but OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
}
|
||||
|
||||
ceilometer_alarm_evaluator_monitor() {
|
||||
local rc
|
||||
local pid
|
||||
|
||||
ceilometer_alarm_evaluator_status
|
||||
rc=$?
|
||||
|
||||
# If status returned anything but success, return that immediately
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
return $rc
|
||||
fi
|
||||
|
||||
ocf_log debug "OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) monitor succeeded"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
ceilometer_alarm_evaluator_start() {
|
||||
local rc
|
||||
|
||||
ceilometer_alarm_evaluator_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_SUCCESS ]; then
|
||||
ocf_log info "OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) already running"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# run the actual ceilometer-alarm-evaluator daemon. Don't use ocf_run as we're sending the tool's output
|
||||
# straight to /dev/null anyway and using ocf_run would break stdout-redirection here.
|
||||
su ${OCF_RESKEY_user} -s /bin/sh -c "${OCF_RESKEY_binary} --config-file=$OCF_RESKEY_config \
|
||||
$OCF_RESKEY_additional_parameters"' >> /dev/null 2>&1 & echo $!' > $OCF_RESKEY_pid
|
||||
|
||||
ocf_log debug "Create pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
# Spin waiting for the server to come up.
|
||||
while true; do
|
||||
ceilometer_alarm_evaluator_monitor
|
||||
rc=$?
|
||||
[ $rc -eq $OCF_SUCCESS ] && break
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) start failed"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
ocf_log info "OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) started"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
ceilometer_alarm_evaluator_stop() {
|
||||
local rc
|
||||
local pid
|
||||
|
||||
ceilometer_alarm_evaluator_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
ocf_log info "OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) already stopped"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# Try SIGTERM
|
||||
pid=`cat $OCF_RESKEY_pid`
|
||||
ocf_run kill -s TERM $pid
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) couldn't be stopped"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
# stop waiting
|
||||
shutdown_timeout=15
|
||||
if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
|
||||
shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5))
|
||||
fi
|
||||
count=0
|
||||
while [ $count -lt $shutdown_timeout ]; do
|
||||
ceilometer_alarm_evaluator_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
break
|
||||
fi
|
||||
count=`expr $count + 1`
|
||||
sleep 1
|
||||
ocf_log debug "OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) still hasn't stopped yet. Waiting ..."
|
||||
done
|
||||
|
||||
ceilometer_alarm_evaluator_status
|
||||
rc=$?
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
# SIGTERM didn't help either, try SIGKILL
|
||||
ocf_log info "OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) failed to stop after ${shutdown_timeout}s \
|
||||
using SIGTERM. Trying SIGKILL ..."
|
||||
ocf_run kill -s KILL $pid
|
||||
fi
|
||||
|
||||
ocf_log info "OpenStack Ceilometer Alarm Evaluator (ceilometer-alarm-evaluator) stopped"
|
||||
|
||||
ocf_log debug "Delete pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
rm -f $OCF_RESKEY_pid
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
case "$1" in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS;;
|
||||
usage|help) usage
|
||||
exit $OCF_SUCCESS;;
|
||||
esac
|
||||
|
||||
# Anything except meta-data and help must pass validation
|
||||
ceilometer_alarm_evaluator_validate || exit $?
|
||||
|
||||
# What kind of method was invoked?
|
||||
case "$1" in
|
||||
start) ceilometer_alarm_evaluator_start;;
|
||||
stop) ceilometer_alarm_evaluator_stop;;
|
||||
status) ceilometer_alarm_evaluator_status;;
|
||||
monitor) ceilometer_alarm_evaluator_monitor;;
|
||||
validate-all) ;;
|
||||
*) usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED;;
|
||||
esac
|
281
files/fuel-ha-utils/ocf/haproxy
Executable file
281
files/fuel-ha-utils/ocf/haproxy
Executable file
@ -0,0 +1,281 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Resource script for haproxy daemon
|
||||
#
|
||||
# Description: Manages haproxy daemon as an OCF resource in
|
||||
# an High Availability setup.
|
||||
#
|
||||
# HAProxy OCF script's Author: Russki
|
||||
# Rsync OCF script's Author: Dhairesh Oza <odhairesh@novell.com>
|
||||
# License: GNU General Public License (GPL)
|
||||
#
|
||||
#
|
||||
# usage: $0 {start|stop|status|monitor|validate-all|meta-data}
|
||||
#
|
||||
# The "start" arg starts haproxy.
|
||||
#
|
||||
# The "stop" arg stops it.
|
||||
#
|
||||
# OCF parameters:
|
||||
# OCF_RESKEY_binpath
|
||||
# OCF_RESKEY_conffile
|
||||
# OCF_RESKEY_extraconf
|
||||
#
|
||||
# Note:This RA requires that the haproxy config files has a "pidfile"
|
||||
# entry so that it is able to act on the correct process
|
||||
##########################################################################
|
||||
# Initialization:
|
||||
|
||||
OCF_RESKEY_conffile_default="/etc/haproxy/haproxy.cfg"
|
||||
OCF_RESKEY_pidfile_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
OCF_RESKEY_binpath_default="/usr/sbin/haproxy"
|
||||
|
||||
: ${OCF_RESKEY_conffile=${OCF_RESKEY_conffile_default}}
|
||||
: ${OCF_RESKEY_pidfile=${OCF_RESKEY_pidfile_default}}
|
||||
: ${OCF_RESKEY_binpath=${OCF_RESKEY_binpath_default}}
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs
|
||||
|
||||
USAGE="Usage: $0 {start|stop|status|monitor|validate-all|meta-data}";
|
||||
|
||||
##########################################################################
|
||||
|
||||
usage()
|
||||
{
|
||||
echo $USAGE >&2
|
||||
}
|
||||
|
||||
meta_data()
|
||||
{
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="haproxy">
|
||||
<version>1.0</version>
|
||||
<longdesc lang="en">
|
||||
This script manages haproxy daemon
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages an haproxy daemon</shortdesc>
|
||||
|
||||
<parameters>
|
||||
|
||||
<parameter name="binpath">
|
||||
<longdesc lang="en">
|
||||
The haproxy binary path.
|
||||
For example, "/usr/sbin/haproxy"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Full path to the haproxy binary</shortdesc>
|
||||
<content type="string" default="/usr/sbin/haproxy"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="conffile">
|
||||
<longdesc lang="en">
|
||||
The haproxy daemon configuration file name with full path.
|
||||
For example, "/etc/haproxy/haproxy.cfg"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Configuration file name with full path</shortdesc>
|
||||
<content type="string" default="/etc/haproxy/haproxy.cfg" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="extraconf">
|
||||
<longdesc lang="en">
|
||||
Extra command line arguments to pass to haproxy.
|
||||
For example, "-f /etc/haproxy/shared.cfg"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Extra command line arguments for haproxy</shortdesc>
|
||||
<content type="string" default="" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20s"/>
|
||||
<action name="stop" timeout="20s"/>
|
||||
<action name="reload" timeout="20s"/>
|
||||
<action name="monitor" depth="0" timeout="20s" interval="60s" />
|
||||
<action name="validate-all" timeout="20s"/>
|
||||
<action name="meta-data" timeout="5s"/>
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
exit $OCF_SUCCESS
|
||||
}
|
||||
|
||||
get_variables()
|
||||
{
|
||||
CONF_FILE="${OCF_RESKEY_conffile}"
|
||||
COMMAND="${OCF_RESKEY_binpath}"
|
||||
|
||||
if [ -n "${OCF_RESKEY_pidfile}" ]; then
|
||||
PIDFILE=$(grep -v "#" ${CONF_FILE} | grep "pidfile" | sed 's/^[ \t]*pidfile[ \t]*//')
|
||||
else
|
||||
PIDFILE="${OCF_RESKEY_pidfile}"
|
||||
fi
|
||||
}
|
||||
|
||||
haproxy_status()
|
||||
{
|
||||
get_variables
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${PIDFILE} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
ocf_log debug "Create pid file dir: ${PID_DIR}"
|
||||
mkdir -p "${PID_DIR}"
|
||||
# no need to chown, root is user for haproxy
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
if [ -n "${PIDFILE}" -a -f "${PIDFILE}" ]; then
|
||||
# haproxy is probably running
|
||||
# get pid from pidfile
|
||||
PID="`cat ${PIDFILE}`"
|
||||
if [ -n "${PID}" ]; then
|
||||
# check if process exists
|
||||
if ps -p "${PID}" | grep -q haproxy; then
|
||||
ocf_log info "haproxy daemon running"
|
||||
return $OCF_SUCCESS
|
||||
else
|
||||
ocf_log info "haproxy daemon is not running but pid file exists"
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
else
|
||||
ocf_log err "PID file empty!"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
# haproxy is not running
|
||||
ocf_log info "haproxy daemon is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
}
|
||||
|
||||
haproxy_start()
|
||||
{
|
||||
get_variables
|
||||
|
||||
# if haproxy is running return success
|
||||
haproxy_status
|
||||
retVal=$?
|
||||
if [ $retVal -eq $OCF_SUCCESS ]; then
|
||||
exit $OCF_SUCCESS
|
||||
elif [ $retVal -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "Error. Unknown status."
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
# run the haproxy binary
|
||||
"${COMMAND}" ${OCF_RESKEY_extraconf} -f "${CONF_FILE}" -p "${PIDFILE}"
|
||||
if [ $? -ne 0 ]; then
|
||||
ocf_log err "Error. haproxy daemon returned error $?."
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
ocf_log info "Started haproxy daemon."
|
||||
exit $OCF_SUCCESS
|
||||
}
|
||||
|
||||
haproxy_reload()
|
||||
{
|
||||
get_variables
|
||||
if haproxy_status; then
|
||||
# get pid from pidfile
|
||||
PID="`cat ${PIDFILE}`"
|
||||
# reload haproxy binary replacing the old process
|
||||
"${COMMAND}" ${OCF_RESKEY_extraconf} -f "${CONF_FILE}" -p "${PIDFILE}" -sf "${PID}"
|
||||
if [ $? -ne 0 ]; then
|
||||
ocf_log err "Error. haproxy daemon returned error $?."
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
else
|
||||
ocf_log info "Haproxy daemon is not running. Starting it."
|
||||
haproxy_start
|
||||
fi
|
||||
}
|
||||
|
||||
haproxy_stop()
|
||||
{
|
||||
get_variables
|
||||
if haproxy_status ; then
|
||||
PID="`cat ${PIDFILE}`"
|
||||
if [ -n "${PID}" ] ; then
|
||||
kill "${PID}"
|
||||
if [ $? -ne 0 ]; then
|
||||
kill -SIGKILL "${PID}"
|
||||
if [ $? -ne 0 ]; then
|
||||
ocf_log err "Error. Could not stop haproxy daemon."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
ocf_log debug "Delete pid file: ${PIDFILE} with content ${PID}"
|
||||
rm -f "${PIDFILE}"
|
||||
fi
|
||||
fi
|
||||
ocf_log info "Stopped haproxy daemon."
|
||||
exit $OCF_SUCCESS
|
||||
}
|
||||
|
||||
haproxy_monitor()
|
||||
{
|
||||
haproxy_status
|
||||
}
|
||||
|
||||
haproxy_validate_all()
|
||||
{
|
||||
get_variables
|
||||
if [ -n "$OCF_RESKEY_binpath" -a ! -x "$OCF_RESKEY_binpath" ]; then
|
||||
ocf_log err "Binary path $OCF_RESKEY_binpath does not exist."
|
||||
exit $OCF_ERR_ARGS
|
||||
fi
|
||||
if [ -n "$OCF_RESKEY_conffile" -a ! -f "$OCF_RESKEY_conffile" ]; then
|
||||
ocf_log err "Config file $OCF_RESKEY_conffile does not exist."
|
||||
exit $OCF_ERR_ARGS
|
||||
fi
|
||||
|
||||
if grep -v "^#" "$CONF_FILE" | grep "pidfile" > /dev/null ; then
|
||||
:
|
||||
else
|
||||
ocf_log err "Error. \"pidfile\" entry required in the haproxy config file by haproxy OCF RA."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Main
|
||||
#
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
usage
|
||||
exit $OCF_ERR_ARGS
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
start) haproxy_start
|
||||
;;
|
||||
|
||||
stop) haproxy_stop
|
||||
;;
|
||||
|
||||
reload) haproxy_reload
|
||||
;;
|
||||
|
||||
status) haproxy_status
|
||||
;;
|
||||
|
||||
monitor) haproxy_monitor
|
||||
;;
|
||||
|
||||
validate-all) haproxy_validate_all
|
||||
;;
|
||||
|
||||
meta-data) meta_data
|
||||
;;
|
||||
|
||||
usage) usage; exit $OCF_SUCCESS
|
||||
;;
|
||||
|
||||
*) usage; exit $OCF_ERR_UNIMPLEMENTED
|
||||
;;
|
||||
esac
|
353
files/fuel-ha-utils/ocf/heat_engine_centos
Normal file
353
files/fuel-ha-utils/ocf/heat_engine_centos
Normal file
@ -0,0 +1,353 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# OpenStack Heat Engine OCF script
|
||||
#
|
||||
# Description: Manages OpenStack Heat Engine process as a HA resource
|
||||
#
|
||||
# Authors: Mirantis inc.
|
||||
#
|
||||
# Support: openstack@lists.launchpad.net
|
||||
# License: Apache Software License (ASL) 2.0
|
||||
#
|
||||
# See usage() function below for more details ...
|
||||
#
|
||||
# OCF instance parameters:
|
||||
# OCF_RESKEY_binary
|
||||
# OCF_RESKEY_config
|
||||
# OCF_RESKEY_user
|
||||
# OCF_RESKEY_pid
|
||||
# OCF_RESKEY_amqp_server_port
|
||||
# OCF_RESKEY_additional_parameters
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
#######################################################################
|
||||
|
||||
# Fill in some defaults if no values are specified
|
||||
|
||||
SERVICE_NAME="OpenStack Heat Engine"
|
||||
LOG="/var/log/heat/heat-engine.log"
|
||||
|
||||
OCF_RESKEY_binary_default="/usr/bin/heat-engine"
|
||||
OCF_RESKEY_config_default="/etc/heat/heat.conf"
|
||||
OCF_RESKEY_pid_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
OCF_RESKEY_amqp_server_port_default="5673"
|
||||
OCF_RESKEY_user_default="heat"
|
||||
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
: ${OCF_RESKEY_amqp_server_port=${OCF_RESKEY_amqp_server_port_default}}
|
||||
|
||||
#######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<UEND
|
||||
usage: $0 (start|stop|validate-all|meta-data|status|monitor)
|
||||
|
||||
$0 manages the ${SERVICE_NAME} process as an HA resource
|
||||
|
||||
The 'start' operation starts the ${SERVICE_NAME}
|
||||
The 'stop' operation stops the ${SERVICE_NAME}
|
||||
The 'validate-all' operation reports whether the parameters are valid
|
||||
The 'meta-data' operation reports this RA's meta-data information
|
||||
The 'status' operation reports whether the ${SERVICE_NAME} is running
|
||||
The 'monitor' operation reports whether the ${SERVICE_NAME} is running
|
||||
|
||||
UEND
|
||||
}
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="heat-engine">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
Manages OpenStack Heat Engine daemon as a Pacemaker Resource.
|
||||
Heat is used to deploy instances based on predefined templates.
|
||||
There should be only one active instace of Heat Engine in an OpenStack cluster.
|
||||
Heat Engine connects to its databse and uses AMQP service to communicate with
|
||||
Heat API's processes ans REST interface to communicate with Nova API.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages OpenStack Heat</shortdesc>
|
||||
<parameters>
|
||||
|
||||
<parameter name="binary" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Name of Heat's binary file that will be run.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Heat binary file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binary_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Path to configuration file used by Heat Engine daemon
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Heat configuration file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="user" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
User running Heat Engine
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Heat user</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_user_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pid" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The pid file to use for this process
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Heat pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pid_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="amqp_server_port" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The listening port number of the AMQP server. Use for monitoring purposes
|
||||
</longdesc>
|
||||
<shortdesc lang="en">AMQP listening port</shortdesc>
|
||||
<content type="integer" default="${OCF_RESKEY_amqp_server_port_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="additional_parameters" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Additional parameters to pass on to the Heat engine if you do need them
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Additional parameters for the Heat engine</shortdesc>
|
||||
<content type="string" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20" />
|
||||
<action name="stop" timeout="20" />
|
||||
<action name="status" timeout="20" />
|
||||
<action name="monitor" timeout="30" interval="20" />
|
||||
<action name="validate-all" timeout="5" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Functions invoked by resource manager actions
|
||||
|
||||
heat_engine_check_port() {
|
||||
# This function has been taken from the squid RA and improved a bit
|
||||
# The length of the integer must be 4
|
||||
# Examples of valid port: "1080", "0080"
|
||||
# Examples of invalid port: "1080bad", "0", "0000", ""
|
||||
|
||||
local int
|
||||
local cnt
|
||||
|
||||
int="$1"
|
||||
cnt=${#int}
|
||||
echo $int |egrep -qx '[0-9]+(:[0-9]+)?(,[0-9]+(:[0-9]+)?)*'
|
||||
|
||||
if [ $? -ne 0 ] || [ $cnt -ne 4 ]; then
|
||||
ocf_log err "Invalid port number: $1"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
}
|
||||
|
||||
service_validate() {
|
||||
local rc
|
||||
|
||||
check_binary $OCF_RESKEY_binary
|
||||
check_binary netstat
|
||||
heat_engine_check_port $OCF_RESKEY_amqp_server_port
|
||||
|
||||
# A config file on shared storage that is not available
|
||||
# during probes is OK.
|
||||
if [ ! -f $OCF_RESKEY_config ]; then
|
||||
if ! ocf_is_probe; then
|
||||
ocf_log err "Config $OCF_RESKEY_config doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
ocf_log_warn "Config $OCF_RESKEY_config not available during a probe"
|
||||
fi
|
||||
|
||||
getent passwd $OCF_RESKEY_user >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "User $OCF_RESKEY_user doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
service_status() {
|
||||
local pid
|
||||
local rc
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${OCF_RESKEY_pid} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
mkdir -p "${PID_DIR}"
|
||||
chown -R ${OCF_RESKEY_user} "${PID_DIR}"
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
if [ ! -f $OCF_RESKEY_pid ]; then
|
||||
ocf_log info "${SERVICE_NAME} is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
else
|
||||
pid=`cat $OCF_RESKEY_pid`
|
||||
fi
|
||||
|
||||
if [ -n "${pid}" ]; then
|
||||
ocf_run -warn kill -s 0 $pid
|
||||
rc=$?
|
||||
else
|
||||
ocf_log err "PID file ${OCF_RESKEY_pid} is empty!"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
if [ $rc -eq 0 ]; then
|
||||
return $OCF_SUCCESS
|
||||
else
|
||||
ocf_log info "Old PID file found, but ${SERVICE_NAME} is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
}
|
||||
|
||||
service_monitor() {
|
||||
local rc
|
||||
local pid
|
||||
local rc_amqp
|
||||
local engine_amqp_check
|
||||
|
||||
service_status
|
||||
rc=$?
|
||||
|
||||
# If status returned anything but success, return that immediately
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
return $rc
|
||||
fi
|
||||
|
||||
ocf_log debug "OpenStack Orchestration Engine (heat-engine) monitor succeeded"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
service_start() {
|
||||
local rc
|
||||
|
||||
service_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_SUCCESS ]; then
|
||||
ocf_log info "${SERVICE_NAME} is already running"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# source init and venv
|
||||
. /etc/rc.d/init.d/functions
|
||||
# run the actual daemon.
|
||||
daemon --user "${OCF_RESKEY_user}" --pidfile "${OCF_RESKEY_pid}" "${OCF_RESKEY_binary} --config-file ${OCF_RESKEY_config} --logfile ${LOG} &>/dev/null & echo \$! > ${OCF_RESKEY_pid}"
|
||||
|
||||
# Spin waiting for the server to come up.
|
||||
# Let the CRM/LRM time us out if required
|
||||
while true; do
|
||||
service_monitor
|
||||
rc=$?
|
||||
[ $rc -eq $OCF_SUCCESS ] && break
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "${SERVICE_NAME} start failed"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
ocf_log info "${SERVICE_NAME} started"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
service_stop() {
|
||||
local rc
|
||||
local pid
|
||||
|
||||
service_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
ocf_log info "${SERVICE_NAME} is already stopped"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# Try SIGTERM
|
||||
pid=`cat $OCF_RESKEY_pid`
|
||||
ocf_run kill -s TERM $pid
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "${SERVICE_NAME} couldn't be stopped"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
# stop waiting
|
||||
shutdown_timeout=15
|
||||
if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
|
||||
shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5))
|
||||
fi
|
||||
count=0
|
||||
while [ $count -lt $shutdown_timeout ]; do
|
||||
service_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
break
|
||||
fi
|
||||
count=`expr $count + 1`
|
||||
sleep 1
|
||||
ocf_log debug "${SERVICE_NAME} still hasn't stopped yet. Waiting ..."
|
||||
done
|
||||
|
||||
service_status
|
||||
rc=$?
|
||||
if [ "${rc}" -ne "${OCF_NOT_RUNNING}" ]; then
|
||||
# SIGTERM didn't help either, try SIGKILL
|
||||
ocf_log info "${SERVICE_NAME} failed to stop after ${shutdown_timeout}s using SIGTERM. Trying SIGKILL ..."
|
||||
ocf_run kill -s KILL "${pid}"
|
||||
fi
|
||||
|
||||
ocf_log info "${SERVICE_NAME} stopped"
|
||||
|
||||
ocf_log debug "Delete pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
rm -f "${OCF_RESKEY_pid}"
|
||||
|
||||
return "${OCF_SUCCESS}"
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
case "$1" in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS;;
|
||||
usage|help) usage
|
||||
exit $OCF_SUCCESS;;
|
||||
esac
|
||||
|
||||
# Anything except meta-data and help must pass validation
|
||||
service_validate || exit $?
|
||||
|
||||
# What kind of method was invoked?
|
||||
case "$1" in
|
||||
start) service_start;;
|
||||
stop) service_stop;;
|
||||
status) service_status;;
|
||||
monitor) service_monitor;;
|
||||
validate-all) ;;
|
||||
*) usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED;;
|
||||
esac
|
||||
|
||||
|
354
files/fuel-ha-utils/ocf/heat_engine_ubuntu
Normal file
354
files/fuel-ha-utils/ocf/heat_engine_ubuntu
Normal file
@ -0,0 +1,354 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# OpenStack Heat Engine OCF script
|
||||
#
|
||||
# Description: Manages OpenStack Heat Engine process as a HA resource
|
||||
#
|
||||
# Authors: Mirantis inc.
|
||||
#
|
||||
# Support: openstack@lists.launchpad.net
|
||||
# License: Apache Software License (ASL) 2.0
|
||||
#
|
||||
# See usage() function below for more details ...
|
||||
#
|
||||
# OCF instance parameters:
|
||||
# OCF_RESKEY_binary
|
||||
# OCF_RESKEY_config
|
||||
# OCF_RESKEY_user
|
||||
# OCF_RESKEY_pid
|
||||
# OCF_RESKEY_amqp_server_port
|
||||
# OCF_RESKEY_additional_parameters
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
#######################################################################
|
||||
|
||||
# Fill in some defaults if no values are specified
|
||||
|
||||
SERVICE_NAME="OpenStack Heat Engine"
|
||||
LOG="/var/log/heat/heat-engine.log"
|
||||
|
||||
OCF_RESKEY_binary_default="/usr/bin/heat-engine"
|
||||
OCF_RESKEY_config_default="/etc/heat/heat.conf"
|
||||
OCF_RESKEY_pid_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
OCF_RESKEY_amqp_server_port_default="5673"
|
||||
OCF_RESKEY_user_default="heat"
|
||||
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
: ${OCF_RESKEY_amqp_server_port=${OCF_RESKEY_amqp_server_port_default}}
|
||||
|
||||
#######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<UEND
|
||||
usage: $0 (start|stop|validate-all|meta-data|status|monitor)
|
||||
|
||||
$0 manages the ${SERVICE_NAME} process as an HA resource
|
||||
|
||||
The 'start' operation starts the ${SERVICE_NAME}
|
||||
The 'stop' operation stops the ${SERVICE_NAME}
|
||||
The 'validate-all' operation reports whether the parameters are valid
|
||||
The 'meta-data' operation reports this RA's meta-data information
|
||||
The 'status' operation reports whether the ${SERVICE_NAME} is running
|
||||
The 'monitor' operation reports whether the ${SERVICE_NAME} is running
|
||||
|
||||
UEND
|
||||
}
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="heat-engine">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
Manages OpenStack Heat Engine daemon as a Pacemaker Resource.
|
||||
Heat is used to deploy instances based on predefined templates.
|
||||
There should be only one active instace of Heat Engine in an OpenStack cluster.
|
||||
Heat Engine connects to its databse and uses AMQP service to communicate with
|
||||
Heat API's processes ans REST interface to communicate with Nova API.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages OpenStack Heat</shortdesc>
|
||||
<parameters>
|
||||
|
||||
<parameter name="binary" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Name of Heat's binary file that will be run.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Heat binary file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binary_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Path to configuration file used by Heat Engine daemon
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Heat configuration file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="user" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
User running Heat Engine
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Heat user</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_user_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pid" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The pid file to use for this process
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Heat pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pid_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="amqp_server_port" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The listening port number of the AMQP server. Use for monitoring purposes
|
||||
</longdesc>
|
||||
<shortdesc lang="en">AMQP listening port</shortdesc>
|
||||
<content type="integer" default="${OCF_RESKEY_amqp_server_port_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="additional_parameters" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Additional parameters to pass on to the Heat engine if you do need them
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Additional parameters for the Heat engine</shortdesc>
|
||||
<content type="string" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20" />
|
||||
<action name="stop" timeout="20" />
|
||||
<action name="status" timeout="20" />
|
||||
<action name="monitor" timeout="30" interval="20" />
|
||||
<action name="validate-all" timeout="5" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Functions invoked by resource manager actions
|
||||
|
||||
heat_engine_check_port() {
|
||||
# This function has been taken from the squid RA and improved a bit
|
||||
# The length of the integer must be 4
|
||||
# Examples of valid port: "1080", "0080"
|
||||
# Examples of invalid port: "1080bad", "0", "0000", ""
|
||||
|
||||
local int
|
||||
local cnt
|
||||
|
||||
int="$1"
|
||||
cnt=${#int}
|
||||
echo $int |egrep -qx '[0-9]+(:[0-9]+)?(,[0-9]+(:[0-9]+)?)*'
|
||||
|
||||
if [ $? -ne 0 ] || [ $cnt -ne 4 ]; then
|
||||
ocf_log err "Invalid port number: $1"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
}
|
||||
|
||||
service_validate() {
|
||||
local rc
|
||||
|
||||
check_binary $OCF_RESKEY_binary
|
||||
check_binary netstat
|
||||
heat_engine_check_port $OCF_RESKEY_amqp_server_port
|
||||
|
||||
# A config file on shared storage that is not available
|
||||
# during probes is OK.
|
||||
if [ ! -f $OCF_RESKEY_config ]; then
|
||||
if ! ocf_is_probe; then
|
||||
ocf_log err "Config $OCF_RESKEY_config doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
ocf_log_warn "Config $OCF_RESKEY_config not available during a probe"
|
||||
fi
|
||||
|
||||
getent passwd $OCF_RESKEY_user >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "User $OCF_RESKEY_user doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
service_status() {
|
||||
local pid
|
||||
local rc
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${OCF_RESKEY_pid} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
ocf_log debug "Create pid file dir: ${PID_DIR} and chown to ${OCF_RESKEY_user}"
|
||||
mkdir -p "${PID_DIR}"
|
||||
chown -R ${OCF_RESKEY_user} "${PID_DIR}"
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
if [ ! -f $OCF_RESKEY_pid ]; then
|
||||
ocf_log info "${SERVICE_NAME} is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
else
|
||||
pid=`cat $OCF_RESKEY_pid`
|
||||
fi
|
||||
|
||||
if [ -n "${pid}" ]; then
|
||||
ocf_run -warn kill -s 0 $pid
|
||||
rc=$?
|
||||
else
|
||||
ocf_log err "PID file ${OCF_RESKEY_pid} is empty!"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
if [ $rc -eq 0 ]; then
|
||||
return $OCF_SUCCESS
|
||||
else
|
||||
ocf_log info "Old PID file found, but ${SERVICE_NAME} is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
}
|
||||
|
||||
service_monitor() {
|
||||
local rc
|
||||
local pid
|
||||
local rc_amqp
|
||||
local engine_amqp_check
|
||||
|
||||
service_status
|
||||
rc=$?
|
||||
|
||||
# If status returned anything but success, return that immediately
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
return $rc
|
||||
fi
|
||||
|
||||
ocf_log debug "OpenStack Orchestration Engine (heat-engine) monitor succeeded"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
service_start() {
|
||||
local rc
|
||||
|
||||
service_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_SUCCESS ]; then
|
||||
ocf_log info "${SERVICE_NAME} is already running"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# source init and venv
|
||||
. /lib/lsb/init-functions
|
||||
# run the actual daemon.
|
||||
start-stop-daemon --start --background --quiet --chuid "${OCF_RESKEY_user}:${OCF_RESKEY_user}" --make-pidfile --pidfile "${OCF_RESKEY_pid}" --startas "${OCF_RESKEY_binary}"
|
||||
|
||||
# Spin waiting for the server to come up.
|
||||
# Let the CRM/LRM time us out if required
|
||||
while true; do
|
||||
service_monitor
|
||||
rc=$?
|
||||
[ $rc -eq $OCF_SUCCESS ] && break
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "${SERVICE_NAME} start failed"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
ocf_log info "${SERVICE_NAME} started"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
service_stop() {
|
||||
local rc
|
||||
local pid
|
||||
|
||||
service_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
ocf_log info "${SERVICE_NAME} is already stopped"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# Try SIGTERM
|
||||
pid=`cat $OCF_RESKEY_pid`
|
||||
ocf_run kill -s TERM $pid
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "${SERVICE_NAME} couldn't be stopped"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
# stop waiting
|
||||
shutdown_timeout=15
|
||||
if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
|
||||
shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5))
|
||||
fi
|
||||
count=0
|
||||
while [ $count -lt $shutdown_timeout ]; do
|
||||
service_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
break
|
||||
fi
|
||||
count=`expr $count + 1`
|
||||
sleep 1
|
||||
ocf_log debug "${SERVICE_NAME} still hasn't stopped yet. Waiting ..."
|
||||
done
|
||||
|
||||
service_status
|
||||
rc=$?
|
||||
if [ "${rc}" -ne "${OCF_NOT_RUNNING}" ]; then
|
||||
# SIGTERM didn't help either, try SIGKILL
|
||||
ocf_log info "${SERVICE_NAME} failed to stop after ${shutdown_timeout}s using SIGTERM. Trying SIGKILL ..."
|
||||
ocf_run kill -s KILL "${pid}"
|
||||
fi
|
||||
|
||||
ocf_log info "${SERVICE_NAME} stopped"
|
||||
|
||||
ocf_log debug "Delete pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
rm -f "${OCF_RESKEY_pid}"
|
||||
|
||||
return "${OCF_SUCCESS}"
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
case "$1" in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS;;
|
||||
usage|help) usage
|
||||
exit $OCF_SUCCESS;;
|
||||
esac
|
||||
|
||||
# Anything except meta-data and help must pass validation
|
||||
service_validate || exit $?
|
||||
|
||||
# What kind of method was invoked?
|
||||
case "$1" in
|
||||
start) service_start;;
|
||||
stop) service_stop;;
|
||||
status) service_status;;
|
||||
monitor) service_monitor;;
|
||||
validate-all) ;;
|
||||
*) usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED;;
|
||||
esac
|
||||
|
||||
|
701
files/fuel-ha-utils/ocf/mysql-wss
Normal file
701
files/fuel-ha-utils/ocf/mysql-wss
Normal file
@ -0,0 +1,701 @@
|
||||
#!/bin/bash
|
||||
# Authors: Bartosz Kupidura (Mirantis): Rewrite RA to support mysql/galera
|
||||
# Sergii Golovatiuk (Mirantis): Rewrite RA to support mysql/galera
|
||||
# Alan Robertson: DB2 Script
|
||||
# Jakub Janczak: rewrite as MySQL
|
||||
# Andrew Beekhof: cleanup and import
|
||||
# Sebastian Reitenbach: add OpenBSD defaults, more cleanup
|
||||
# Narayan Newton: add Gentoo/Debian defaults
|
||||
# Marian Marinov, Florian Haas: add replication capability
|
||||
# Yves Trudeau, Baron Schwartz: add VIP support and improve replication
|
||||
#
|
||||
# Support: openstack@lists.launchpad.net
|
||||
# License: GNU General Public License (GPL)
|
||||
#
|
||||
# (c) 2002-2005 International Business Machines, Inc.
|
||||
# 2005-2010 Linux-HA contributors
|
||||
# 2014 Mirantis Inc.
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
#######################################################################
|
||||
# Fill in some defaults if no values are specified
|
||||
OCF_RESKEY_binary_default="/usr/bin/mysqld_safe"
|
||||
OCF_RESKEY_client_binary_default="/usr/bin/mysql"
|
||||
OCF_RESKEY_config_default="/etc/my.cnf"
|
||||
OCF_RESKEY_datadir_default="/var/lib/mysql"
|
||||
OCF_RESKEY_user_default="mysql"
|
||||
OCF_RESKEY_group_default="mysql"
|
||||
OCF_RESKEY_pid_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
OCF_RESKEY_socket_default="/var/lib/mysql/mysql.sock"
|
||||
OCF_RESKEY_test_user_default="root"
|
||||
OCF_RESKEY_test_passwd_default=""
|
||||
OCF_RESKEY_additional_parameters_default=""
|
||||
OCF_RESKEY_master_timeout_default="300"
|
||||
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
MYSQL_BINDIR="$(dirname ${OCF_RESKEY_binary})"
|
||||
|
||||
: ${OCF_RESKEY_client_binary=${OCF_RESKEY_client_binary_default}}
|
||||
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_datadir=${OCF_RESKEY_datadir_default}}
|
||||
|
||||
: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_group=${OCF_RESKEY_group_default}}
|
||||
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
: ${OCF_RESKEY_socket=${OCF_RESKEY_socket_default}}
|
||||
|
||||
: ${OCF_RESKEY_test_user=${OCF_RESKEY_test_user_default}}
|
||||
: ${OCF_RESKEY_test_passwd=${OCF_RESKEY_test_passwd_default}}
|
||||
|
||||
: ${OCF_RESKEY_additional_parameters=${OCF_RESKEY_additional_parameters_default}}
|
||||
: ${OCF_RESKEY_master_timeout=${OCF_RESKEY_master_timeout_default}}
|
||||
|
||||
#######################################################################
|
||||
# Convenience variables
|
||||
MYSQL=$OCF_RESKEY_client_binary
|
||||
HOSTNAME=$(uname -n)
|
||||
MYSQL_OPTIONS_LOCAL="-S $OCF_RESKEY_socket --connect_timeout=10"
|
||||
MYSQL_OPTIONS_TEST="$MYSQL_OPTIONS_LOCAL --user=$OCF_RESKEY_test_user --password=$OCF_RESKEY_test_passwd"
|
||||
#######################################################################
|
||||
usage() {
|
||||
cat <<UEND
|
||||
usage: $0 (start|stop|meta-data|validate-all|monitor)
|
||||
|
||||
$0 manages a MySQL Database as an HA resource.
|
||||
|
||||
The 'start' operation starts the database.
|
||||
The 'stop' operation stops the database.
|
||||
The 'monitor' operation reports whether the database seems to be working
|
||||
The 'validate-all' operation reports whether the parameters are valid
|
||||
|
||||
UEND
|
||||
}
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="mysql" version="0.1">
|
||||
<version>0.1</version>
|
||||
<longdesc lang="en">
|
||||
Resource script for MySQL
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Resource script for MySQL</shortdesc>
|
||||
<parameters>
|
||||
<parameter name="binary" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the MySQL server binary
|
||||
</longdesc>
|
||||
<shortdesc lang="en">MySQL server binary</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binary_default}" />
|
||||
</parameter>
|
||||
<parameter name="client_binary" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the MySQL client binary
|
||||
</longdesc>
|
||||
<shortdesc lang="en">MySQL client binary</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_client_binary_default}" />
|
||||
</parameter>
|
||||
<parameter name="config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">MySQL config</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_config_default}" />
|
||||
</parameter>
|
||||
<parameter name="datadir" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Directory containing databases
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Data directory</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_datadir_default}" />
|
||||
</parameter>
|
||||
<parameter name="user" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
User running MySQL daemon
|
||||
</longdesc>
|
||||
<shortdesc lang="en">MySQL user</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_user_default}" />
|
||||
</parameter>
|
||||
<parameter name="group" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Group running MySQL daemon (for logfile and directory permissions)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">MySQL group</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_group_default}"/>
|
||||
</parameter>
|
||||
<parameter name="pid" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The pidfile to be used for mysqld.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">MySQL pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pid_default}"/>
|
||||
</parameter>
|
||||
<parameter name="socket" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The socket to be used for mysqld.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">MySQL socket</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_socket_default}"/>
|
||||
</parameter>
|
||||
<parameter name="test_user" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
MySQL test user, must have select privilege on 'show status'
|
||||
</longdesc>
|
||||
<shortdesc lang="en">MySQL test user</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_test_user_default}" />
|
||||
</parameter>
|
||||
<parameter name="test_passwd" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
MySQL test user password
|
||||
</longdesc>
|
||||
<shortdesc lang="en">MySQL test user password</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_test_passwd_default}" />
|
||||
</parameter>
|
||||
<parameter name="additional_parameters" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Additional parameters which are passed to the mysqld on startup.
|
||||
(e.g. --skip-external-locking or --skip-grant-tables)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Additional parameters to pass to mysqld</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_additional_parameters_default}"/>
|
||||
</parameter>
|
||||
<parameter name="master_timeout" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
How long we should wait for galera master. If master not come up before timeout,
|
||||
RA will choose new master from already running nodes. This value can by changed by crm_attribute:
|
||||
# crm_attribute --name galera_master_timeout --update 500
|
||||
Remember to remove this after maintenance. USE WITH CAUTION!
|
||||
Remember to change timeout for start operation. Start timeout should be bigger than master_timeout
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Galera master timeout</shortdesc>
|
||||
<content type="integer" default="${OCF_RESKEY_master_timeout_default}"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
<actions>
|
||||
<action name="start" timeout="330" />
|
||||
<action name="stop" timeout="120" />
|
||||
<action name="monitor" timeout="30" interval="20" depth="0" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
<action name="validate-all" timeout="10" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
# Convenience functions
|
||||
#######################################################################
|
||||
nodes_in_cluster_online() {
|
||||
local NODES
|
||||
|
||||
NODES=$(crm_node --partition | sed -e '/(null)/d')
|
||||
if [ ! -z "$NODES" ]; then
|
||||
echo $NODES
|
||||
else
|
||||
echo
|
||||
fi
|
||||
}
|
||||
nodes_in_cluster() {
|
||||
local NODES
|
||||
|
||||
#Ubuntu doesn't like \w
|
||||
NODES=$(crm_node --list | awk '/^[a-zA-Z0-9]/ {print $2}' | sed -e '/(null)/d')
|
||||
if [ ! -z "$NODES" ]; then
|
||||
echo $NODES
|
||||
else
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
#Validate if GTID have correct format (return 0), else return 1
|
||||
#valid values are:
|
||||
#XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX:123 - standard cluster-id:commit-id
|
||||
#XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX:-1 - standard non initialized cluster, 00000000-0000-0000-0000-000000000000:-1
|
||||
validate_gtid() {
|
||||
local rc
|
||||
local status_loglevel="err"
|
||||
|
||||
if [ -z $1 ]; then
|
||||
ocf_log $status_loglevel "No GTID provided"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo $1 | grep -q -E '^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}:([[:digit:]]|-1)'
|
||||
rc=$?
|
||||
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log $status_loglevel "GTID have wrong format: $1"
|
||||
return 1
|
||||
else
|
||||
ocf_log info "GTID OK: $1"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
#Get galera GTID from local mysql instance
|
||||
update_node_gtid() {
|
||||
local status_loglevel="err"
|
||||
local GTID
|
||||
|
||||
# Set loglevel to info during probe
|
||||
if ocf_is_probe; then
|
||||
status_loglevel="info"
|
||||
fi
|
||||
|
||||
if mysql_status $status_loglevel 1; then
|
||||
CLUSTER_ID=$($MYSQL $MYSQL_OPTIONS_TEST -s -N \
|
||||
-e "SHOW STATUS LIKE 'wsrep_local_state_uuid'" | awk '{print $NF}')
|
||||
COMMIT_ID=$($MYSQL $MYSQL_OPTIONS_TEST -s -N \
|
||||
-e "SHOW STATUS LIKE 'wsrep_last_committed'" | awk '{print $NF}')
|
||||
GTID="$CLUSTER_ID:$COMMIT_ID"
|
||||
else
|
||||
GTID=$(cat ${OCF_RESKEY_datadir}/grastate.dat \
|
||||
| awk '/uuid/ { uuid = $NF} /seqno/ { seqno = $NF} END {print uuid":"seqno}')
|
||||
fi
|
||||
|
||||
#Final try to recover
|
||||
if [ -z ${GTID} ]; then
|
||||
GTID=$(${OCF_RESKEY_binary} --wsrep-recover \
|
||||
--log-error=/dev/stdout 2>&1 | grep 'Recovered position' | awk '{print $NF}')
|
||||
fi
|
||||
|
||||
if validate_gtid "$GTID"; then
|
||||
ocf_log info "Galera GTID: ${GTID}"
|
||||
crm_attribute --quiet --node $HOSTNAME --lifetime reboot --name gtid \
|
||||
--update $GTID
|
||||
else
|
||||
ocf_log info "Wrong GTID: ${GTID}, Removing"
|
||||
crm_attribute --quiet --node $HOSTNAME --lifetime reboot --name gtid -D
|
||||
fi
|
||||
}
|
||||
|
||||
get_master_timeout() {
|
||||
local default=$OCF_RESKEY_master_timeout
|
||||
local rc
|
||||
local timeout=$(crm_attribute --quiet --name galera_master_timeout \
|
||||
--query -d $default -q | sed -e '/(null)/d')
|
||||
rc=$?
|
||||
|
||||
if [ $rc -eq 0 ]; then
|
||||
echo $timeout
|
||||
else
|
||||
echo $default
|
||||
fi
|
||||
}
|
||||
|
||||
#Get gtid attribute for $1 node, "0" means no GTID set or wrong format for GTID
|
||||
get_node_gtid() {
|
||||
local rc
|
||||
local GTID
|
||||
|
||||
GTID=$(crm_attribute --quiet --node $1 --lifetime reboot --query \
|
||||
--name gtid 2> /dev/null | sed -e '/(null)/d')
|
||||
rc=$?
|
||||
|
||||
if [ $rc -ne 0 -o -z "$GTID" ]; then
|
||||
ocf_log info "No GTID for $1"
|
||||
echo 0
|
||||
else
|
||||
if validate_gtid "$GTID"; then
|
||||
ocf_log info "Galera GTID: ${GTID}"
|
||||
echo $GTID
|
||||
else
|
||||
ocf_log info "No GTID for $1"
|
||||
echo 0
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
check_if_reelection_needed() {
|
||||
local PARTITION_WITH_QUORUM=$(crm_node -q | sed -e '/(null)/d')
|
||||
local RESOURCE_NAME=$(echo $OCF_RESOURCE_INSTANCE | cut -f1 -d":")
|
||||
local NODE_COUNT=$(nodes_in_cluster | wc -w)
|
||||
local RUNNING_INSTANCES
|
||||
local rc
|
||||
|
||||
if [ $PARTITION_WITH_QUORUM -eq 1 -o $NODE_COUNT -eq 1 ]; then
|
||||
RUNNING_INSTANCES=$(crm_resource \
|
||||
--quiet --locate --resource $RESOURCE_NAME | sed -e '/(null)/d' | wc -l 2> /dev/null)
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_SUCCESS -a $RUNNING_INSTANCES -lt 1 ]; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
choose_master() {
|
||||
local NODES=$1
|
||||
local -A TMP
|
||||
|
||||
for NODE in $NODES; do
|
||||
NODE_ID=$(echo $NODE | md5sum | awk '{print $1}')
|
||||
TMP[$NODE_ID]=$NODE
|
||||
done
|
||||
|
||||
MASTER=$(printf -- '%s\n' "${!TMP[@]}" | sort | head -1)
|
||||
ocf_log info "Choosed master: ${TMP[$MASTER]}"
|
||||
echo ${TMP[$MASTER]}
|
||||
}
|
||||
|
||||
get_possible_masters() {
|
||||
local NODES=$*
|
||||
local POSSIBLE_MASTERS
|
||||
local -A TMP
|
||||
local MASTER_GTID
|
||||
local GTID
|
||||
|
||||
for NODE in $NODES; do
|
||||
GTID=$(get_node_gtid $NODE)
|
||||
TMP[$NODE]=$(echo $GTID|cut -d":" -f 2)
|
||||
done
|
||||
|
||||
MASTER_GTID=$(printf -- '%s\n' "${TMP[@]}" | sort -r | head -1)
|
||||
|
||||
for NODE in $NODES; do
|
||||
if [ $MASTER_GTID -eq ${TMP[$NODE]} ]; then
|
||||
POSSIBLE_MASTERS="$POSSIBLE_MASTERS $NODE"
|
||||
fi
|
||||
done
|
||||
|
||||
ocf_log info "Possible masters: $POSSIBLE_MASTERS"
|
||||
echo $POSSIBLE_MASTERS
|
||||
}
|
||||
|
||||
check_if_galera_pc() {
|
||||
local NODES
|
||||
local MASTERS
|
||||
local timeout=$(get_master_timeout)
|
||||
|
||||
ocf_log info "Checking if Primary Component"
|
||||
|
||||
while [ $timeout -gt 0 ]; do
|
||||
NODES=$(nodes_in_cluster_online)
|
||||
MASTERS=$(get_possible_masters "$NODES")
|
||||
MASTER=$(choose_master "$MASTERS")
|
||||
if [ "$MASTER" = "$HOSTNAME" ]; then
|
||||
ocf_log info "I\'m Primary Component. Join me!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if check_if_reelection_needed; then
|
||||
ocf_log info "My neighbour is Primary Component"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 10
|
||||
(( timeout -= 10 ))
|
||||
ocf_log info "Waiting for master. ${timeout} seconds left"
|
||||
done
|
||||
|
||||
ocf_log info "${HOSTNAME} is not Primary Component"
|
||||
return 0
|
||||
}
|
||||
# Functions invoked by resource manager actions
|
||||
|
||||
mysql_validate() {
|
||||
check_binary $OCF_RESKEY_binary
|
||||
check_binary $OCF_RESKEY_client_binary
|
||||
|
||||
if [ ! -f $OCF_RESKEY_config ]; then
|
||||
ocf_log err "Config $OCF_RESKEY_config doesn't exist";
|
||||
return $OCF_ERR_INSTALLED;
|
||||
fi
|
||||
|
||||
if [ ! -d $OCF_RESKEY_datadir ]; then
|
||||
ocf_log err "Datadir $OCF_RESKEY_datadir doesn't exist";
|
||||
return $OCF_ERR_INSTALLED;
|
||||
fi
|
||||
|
||||
getent passwd $OCF_RESKEY_user >/dev/null 2>&1
|
||||
if [ ! $? -eq 0 ]; then
|
||||
ocf_log err "User $OCF_RESKEY_user doesn't exit";
|
||||
return $OCF_ERR_INSTALLED;
|
||||
fi
|
||||
|
||||
getent group $OCF_RESKEY_group >/dev/null 2>&1
|
||||
if [ ! $? -eq 0 ]; then
|
||||
ocf_log err "Group $OCF_RESKEY_group doesn't exist";
|
||||
return $OCF_ERR_INSTALLED;
|
||||
fi
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
mysql_status() {
|
||||
i=${2:-3}
|
||||
sleeptime=${3:-5}
|
||||
while [ $i -gt 0 ]; do
|
||||
if [ -f "$OCF_RESKEY_pid" ]; then
|
||||
break
|
||||
fi
|
||||
sleep $sleeptime
|
||||
(( i-- ))
|
||||
ocf_log info "PIDFile ${OCF_RESKEY_pid} of MySQL server not found. Sleeping for $sleeptime seconds. ${i} retries left"
|
||||
done
|
||||
|
||||
|
||||
if [ $i -eq 0 ]; then
|
||||
ocf_log $1 "MySQL is not running"
|
||||
return $OCF_NOT_RUNNING;
|
||||
fi
|
||||
|
||||
pid=$(cat $OCF_RESKEY_pid);
|
||||
if [ -d /proc -a -d /proc/1 ]; then
|
||||
[ "u$pid" != "u" -a -d /proc/$pid ]
|
||||
else
|
||||
kill -s 0 $pid >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
return $OCF_SUCCESS;
|
||||
else
|
||||
ocf_log $1 "MySQL is not running"
|
||||
return $OCF_ERR_GENERIC;
|
||||
fi
|
||||
}
|
||||
|
||||
mysql_monitor() {
|
||||
local rc
|
||||
local status_loglevel="err"
|
||||
local WSREP_CONNECTED
|
||||
local WSREP_LOCAL_STATE_COMMENT
|
||||
local WSREP_READY
|
||||
|
||||
# Set loglevel to info during probe
|
||||
if ocf_is_probe; then
|
||||
status_loglevel="info"
|
||||
fi
|
||||
|
||||
update_node_gtid
|
||||
|
||||
mysql_status $status_loglevel
|
||||
rc=$?
|
||||
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
return $rc
|
||||
fi
|
||||
|
||||
WSREP_CONNECTED=$($MYSQL $MYSQL_OPTIONS_TEST -s -N \
|
||||
-e "SHOW STATUS LIKE 'wsrep_connected'" | awk '{print $NF}')
|
||||
rc=$?
|
||||
|
||||
if [ $rc -ne 0 -o "$WSREP_CONNECTED" != "ON" ]; then
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
WSREP_LOCAL_STATE_COMMENT=$($MYSQL $MYSQL_OPTIONS_TEST -s -N \
|
||||
-e "SHOW STATUS LIKE 'wsrep_local_state_comment'" | awk '{print $NF}')
|
||||
rc=$?
|
||||
|
||||
#Synced|Donor|Desync
|
||||
if [ $rc -eq 0 ]; then
|
||||
if [[ "$WSREP_LOCAL_STATE_COMMENT" =~ 'Synced'|'Donor'|'Desync' ]]; then
|
||||
WSREP_READY=$($MYSQL $MYSQL_OPTIONS_TEST -s -N \
|
||||
-e "SHOW STATUS LIKE 'wsrep_ready'" | awk '{print $NF}')
|
||||
rc=$?
|
||||
|
||||
#Synced but wsrep not ready
|
||||
if [ $rc -ne 0 -o "$WSREP_READY" != "ON" ]; then
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
elif [[ "$WSREP_LOCAL_STATE_COMMENT" == 'Initialized' ]]; then
|
||||
ocf_log err 'MySQL lost quorum or uninitialized'
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
|
||||
ocf_log debug "MySQL monitor succeeded";
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
mysql_start() {
|
||||
local NODES
|
||||
|
||||
if mysql_status info 1; then
|
||||
ocf_log info "MySQL already running"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
socket_dir="$( dirname ${OCF_RESKEY_socket} )"
|
||||
if [ ! -d "${socket_dir}" ] ; then
|
||||
ocf_log info "Create socket dir: ${socket_dir} and chown to ${OCF_RESKEY_user}:${OCF_RESKEY_group}"
|
||||
mkdir -p "${socket_dir}"
|
||||
chown ${OCF_RESKEY_user}:${OCF_RESKEY_group} "${socket_dir}"
|
||||
chmod 755 "${socket_dir}"
|
||||
fi
|
||||
|
||||
# check and make PID file dir
|
||||
pid_dir="$( dirname ${OCF_RESKEY_pid} )"
|
||||
if [ ! -d "${pid_dir}" ] ; then
|
||||
ocf_log info "Create PID dir: ${pid_dir} and chown to ${OCF_RESKEY_user}:${OCF_RESKEY_group}"
|
||||
mkdir -p "${pid_dir}"
|
||||
chown -R ${OCF_RESKEY_user}:${OCF_RESKEY_group} "${pid_dir}"
|
||||
chmod 755 "${pid_dir}"
|
||||
fi
|
||||
|
||||
# Regardless of whether we just created the directory or it
|
||||
# already existed, check whether it is writable by the configured
|
||||
# user
|
||||
for dir in $pid_dir $socket_dir; do
|
||||
if ! su -s /bin/sh - $OCF_RESKEY_user -c "test -w $dir"; then
|
||||
ocf_log err "Directory $dir is not writable by $OCF_RESKEY_user"
|
||||
exit $OCF_ERR_PERM;
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -f /tmp/wsrep-init-file ]; then
|
||||
mysql_extra_params="--init-file=/tmp/wsrep-init-file"
|
||||
else
|
||||
mysql_extra_params=""
|
||||
fi
|
||||
|
||||
update_node_gtid
|
||||
check_if_reelection_needed
|
||||
rc=$?
|
||||
|
||||
if [ $rc -eq 1 ]; then
|
||||
check_if_galera_pc
|
||||
rc=$?
|
||||
|
||||
if [ $rc -eq 1 ]; then
|
||||
mysql_extra_params="$mysql_extra_params --wsrep-new-cluster"
|
||||
fi
|
||||
fi
|
||||
|
||||
ocf_log info "Starting MySQL"
|
||||
${OCF_RESKEY_binary} \
|
||||
--pid-file=$OCF_RESKEY_pid \
|
||||
--socket=$OCF_RESKEY_socket \
|
||||
--datadir=$OCF_RESKEY_datadir \
|
||||
--user=$OCF_RESKEY_user $OCF_RESKEY_additional_parameters \
|
||||
$mysql_extra_params >/dev/null 2>&1 &
|
||||
rc=$?
|
||||
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "MySQL start command failed: $rc"
|
||||
return $rc
|
||||
fi
|
||||
|
||||
# Spin waiting for the server to come up.
|
||||
# Let the CRM/LRM time us out if required.
|
||||
while :; do
|
||||
if mysql_status info 1; then
|
||||
break
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
ocf_log info "MySQL started"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
mysql_cleanup() {
|
||||
ocf_log debug "Delete lock file: /var/lock/subsys/mysqld"
|
||||
rm -f /var/lock/subsys/mysqld
|
||||
|
||||
ocf_log debug "Delete sock file: ${OCF_RESKEY_socket}"
|
||||
rm -f $OCF_RESKEY_socket
|
||||
|
||||
ocf_log debug "Delete pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
rm -f $OCF_RESKEY_pid
|
||||
|
||||
}
|
||||
|
||||
mysql_stop() {
|
||||
local rc
|
||||
|
||||
mysql_status info 1
|
||||
rc=$?
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
mysql_cleanup
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
local pid=$(cat $OCF_RESKEY_pid 2>/dev/null)
|
||||
local pgrp=$(ps -o pgid= ${pid})
|
||||
ocf_log info "Sending SIGTERM to PID: ${pid}"
|
||||
/bin/kill -TERM ${pid} > /dev/null
|
||||
rc=$?
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
ocf_log err "MySQL couldn't be stopped"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
# stop waiting
|
||||
shutdown_timeout=20
|
||||
while [ $shutdown_timeout -gt 0 ]; do
|
||||
mysql_status info 1
|
||||
rc=$?
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
/usr/bin/pkill -9 -g ${pgrp} > /dev/null
|
||||
mysql_cleanup
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
sleep 2
|
||||
(( shutdown_timeout -= 2 ))
|
||||
ocf_log info "MySQL still hasn't stopped yet. ${shutdown_timeout} seconds left "
|
||||
done
|
||||
|
||||
mysql_status info 1
|
||||
rc=$?
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log info "MySQL failed to stop using SIGTERM. Sending SIGKILL to PID: ${pid}"
|
||||
/usr/bin/pkill -9 -g ${pgrp} > /dev/null
|
||||
fi
|
||||
|
||||
mysql_cleanup
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
# If DEBUG_LOG is set, make this resource agent easy to debug: set up the
|
||||
# debug log and direct all output to it. Otherwise, redirect to /dev/null.
|
||||
# The log directory must be a directory owned by root, with permissions 0700,
|
||||
# and the log must be writable and not a symlink.
|
||||
##########################################################################
|
||||
DEBUG_LOG="/tmp/mysql.ocf.ra.debug/log"
|
||||
if [ "${DEBUG_LOG}" -a -w "${DEBUG_LOG}" -a ! -L "${DEBUG_LOG}" ]; then
|
||||
DEBUG_LOG_DIR="${DEBUG_LOG%/*}"
|
||||
if [ -d "${DEBUG_LOG_DIR}" ]; then
|
||||
exec 9>>"$DEBUG_LOG"
|
||||
exec 1>&9 2>&9
|
||||
date '+%Y%m%d %H:%M:%S' >&9
|
||||
echo "$*" >&9
|
||||
env | grep OCF_ | sort >&9
|
||||
set -x
|
||||
else
|
||||
exec 9>/dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS;;
|
||||
usage|help) usage
|
||||
exit $OCF_SUCCESS;;
|
||||
esac
|
||||
|
||||
mysql_validate
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
case "$1" in
|
||||
stop) exit $OCF_SUCCESS;;
|
||||
monitor) exit $OCF_NOT_RUNNING;;
|
||||
*) exit $rc;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# What kind of method was invoked?
|
||||
case "$1" in
|
||||
start) mysql_start;;
|
||||
stop) mysql_stop;;
|
||||
monitor) mysql_monitor;;
|
||||
validate-all) exit $OCF_SUCCESS;;
|
||||
*) usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED;;
|
||||
esac
|
||||
# vim: set ts=4 sw=4 tw=0 et :
|
700
files/fuel-ha-utils/ocf/ns_IPaddr2
Executable file
700
files/fuel-ha-utils/ocf/ns_IPaddr2
Executable file
@ -0,0 +1,700 @@
|
||||
#!/bin/bash
|
||||
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
# Defaults
|
||||
|
||||
OCF_RESKEY_cidr_netmask_default="32"
|
||||
OCF_RESKEY_ns_default=""
|
||||
OCF_RESKEY_base_veth_default="" # should be defined
|
||||
OCF_RESKEY_ns_veth_default="" # should be defined
|
||||
OCF_RESKEY_gateway_default="" # can be "none", "link", IPaddr
|
||||
OCF_RESKEY_gateway_metric_default=0 # can be "", or metric value
|
||||
OCF_RESKEY_also_check_interfaces_default="" # can be "", or list of interfaces
|
||||
OCF_RESKEY_enable_forwarding_default=true
|
||||
OCF_RESKEY_other_networks_default=""
|
||||
OCF_RESKEY_bridge_default="" # can be "", or bridge name
|
||||
|
||||
: ${OCF_RESKEY_cidr_netmask=${OCF_RESKEY_cidr_netmask_default}}
|
||||
: ${OCF_RESKEY_ns=${OCF_RESKEY_ns_default}}
|
||||
: ${OCF_RESKEY_base_veth=${OCF_RESKEY_base_veth_default}}
|
||||
: ${OCF_RESKEY_ns_veth=${OCF_RESKEY_ns_veth_default}}
|
||||
: ${OCF_RESKEY_gateway=${OCF_RESKEY_gateway_default}}
|
||||
: ${OCF_RESKEY_gateway_metric=${OCF_RESKEY_gateway_metric_default}}
|
||||
: ${OCF_RESKEY_also_check_interfaces=${OCF_RESKEY_also_check_interfaces_default}}
|
||||
: ${OCF_RESKEY_enable_forwarding=${OCF_RESKEY_enable_forwarding_default}}
|
||||
: ${OCF_RESKEY_other_networks=${OCF_RESKEY_other_networks_default}}
|
||||
: ${OCF_RESKEY_bridge=${OCF_RESKEY_bridge_default}}
|
||||
|
||||
FAMILY='inet'
|
||||
RUN_IN_NS="ip netns exec $OCF_RESKEY_ns "
|
||||
SH="/bin/bash"
|
||||
SENDARP=$HA_BIN/send_arp
|
||||
SENDARPPIDDIR=$HA_RSCTMP
|
||||
SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$OCF_RESKEY_ip"
|
||||
#######################################################################
|
||||
|
||||
#######################################################################
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="IPaddr2">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
This Linux-specific resource manages IP address inside network namespace.
|
||||
</longdesc>
|
||||
|
||||
<shortdesc lang="en">This Linux-specific resource manages IP address inside network namespace.</shortdesc>
|
||||
|
||||
<parameters>
|
||||
<parameter name="ip" unique="1" required="1">
|
||||
<longdesc lang="en">
|
||||
The IPv4 address to be configured in dotted quad notation, for example
|
||||
"192.168.1.1".
|
||||
</longdesc>
|
||||
<shortdesc lang="en">IPv4 address</shortdesc>
|
||||
<content type="string" default="" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="nic" unique="0">
|
||||
<longdesc lang="en">
|
||||
The base network interface on which the IP address will be brought
|
||||
online.
|
||||
If left empty, the script will try and determine this from the
|
||||
routing table.
|
||||
|
||||
Do NOT specify an alias interface in the form eth0:1 or anything here;
|
||||
rather, specify the base interface only.
|
||||
If you want a label, see the iflabel parameter.
|
||||
|
||||
Prerequisite:
|
||||
|
||||
There must be at least one static IP address, which is not managed by
|
||||
the cluster, assigned to the network interface.
|
||||
If you can not assign any static IP address on the interface,
|
||||
modify this kernel parameter:
|
||||
|
||||
sysctl -w net.ipv4.conf.all.promote_secondaries=1 # (or per device)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Network interface</shortdesc>
|
||||
<content type="string"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="cidr_netmask">
|
||||
<longdesc lang="en">
|
||||
The netmask for the interface in CIDR format
|
||||
(e.g., 24 and not 255.255.255.0)
|
||||
|
||||
If unspecified, the script will also try to determine this from the
|
||||
routing table.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">CIDR netmask</shortdesc>
|
||||
<content type="string" default=""/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="iflabel">
|
||||
<longdesc lang="en">
|
||||
You can specify an additional label for your IP address here.
|
||||
This label is appended to your interface name.
|
||||
|
||||
A label can be specified in nic parameter but it is deprecated.
|
||||
If a label is specified in nic name, this parameter has no effect.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Interface label</shortdesc>
|
||||
<content type="string" default=""/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="ns">
|
||||
<longdesc lang="en">
|
||||
Name of network namespace.\n
|
||||
Should be present.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Name of network namespace.</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_ns_default"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="base_veth">
|
||||
<longdesc lang="en">
|
||||
Name of base system side veth pair tail.\n
|
||||
Should be present.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Name of base system side veth pair tail.</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_base_veth_default"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="ns_veth">
|
||||
<longdesc lang="en">
|
||||
Name of net.namespace side veth pair tail.\n
|
||||
Should be present.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Name of net.namespace side veth pair tail.</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_ns_veth_default"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="gateway">
|
||||
<longdesc lang="en">
|
||||
Default route address.\n
|
||||
Can be "", "link" or IP address.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Default route address.</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_gateway_default"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="gateway_metric">
|
||||
<longdesc lang="en">
|
||||
Default route address.\n
|
||||
Can be "", "link" or IP address.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Default route address.</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_gateway_metric_default"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="setup_forwarding">
|
||||
<longdesc lang="en">
|
||||
Setup forwarding on base system.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Setup forwarding.</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_setup_forwarding_default"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="iptables_start_rules">
|
||||
<longdesc lang="en">
|
||||
Iptables rules that should be started along with IP.\n
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Iptables rules associated with IP start.</shortdesc>
|
||||
<content type="string" default=""/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="iptables_stop_rules">
|
||||
<longdesc lang="en">
|
||||
Iptables rules that should be stopped along with IP.\n
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Iptables rules associated with IP stop.</shortdesc>
|
||||
<content type="string" default=""/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="ns_iptables_start_rules">
|
||||
<longdesc lang="en">
|
||||
Iptables rules that should be started along with IP in the namespace.\n
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Iptables rules associated with IP start in ns.</shortdesc>
|
||||
<content type="string" default=""/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="ns_iptables_stop_rules">
|
||||
<longdesc lang="en">
|
||||
Iptables rules that should be stopped along with IP in the namespace.\n
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Iptables rules associated with IP stop in ns.</shortdesc>
|
||||
<content type="string" default=""/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="iptables_comment">
|
||||
<longdesc lang="en">
|
||||
Iptables comment to associate with rules.\n
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Iptables comment to associate with rules.</shortdesc>
|
||||
<content type="string" default="default-comment"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="also_check_interfaces">
|
||||
<longdesc lang="en">
|
||||
Network interfaces list (ex. NIC), that should be in UP state for monitor action returns succesful.\n
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Network interfaces list (ex. NIC), that should be in UP state for monitor action returns succesful.</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_also_check_interfaces_default"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="other_networks">
|
||||
<longdesc lang="en">
|
||||
Additional routes that should be added to this resource. Routes will be added via value ns_veth.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">List of addtional routes to add routes for.</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_other_networks_default"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="bridge">
|
||||
<longdesc lang="en">
|
||||
Name of the bridge that has ns_veth connected to it.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Name of the bridge.</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_bridge"/>
|
||||
</parameter>
|
||||
|
||||
|
||||
</parameters>
|
||||
<actions>
|
||||
<action name="start" timeout="20s" />
|
||||
<action name="stop" timeout="20s" />
|
||||
<action name="status" depth="0" timeout="20s" interval="10s" />
|
||||
<action name="monitor" depth="0" timeout="20s" interval="10s" />
|
||||
<action name="meta-data" timeout="5s" />
|
||||
<action name="validate-all" timeout="20s" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
|
||||
exit $OCF_SUCCESS
|
||||
}
|
||||
|
||||
|
||||
ip_validate() {
|
||||
|
||||
if [[ X`uname -s` != "XLinux" ]] ; then
|
||||
ocf_log err "ns_IPaddr2 only supported Linux."
|
||||
exit $OCF_ERR_INSTALLED
|
||||
fi
|
||||
|
||||
if [[ -z $OCF_RESKEY_ip ]] ; then
|
||||
ocf_log err "IP address not given"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
|
||||
if [[ -z $OCF_RESKEY_ns ]] ; then
|
||||
ocf_log err "Network namespace not given"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
|
||||
if [[ -z $OCF_RESKEY_cidr_netmask ]] ; then
|
||||
ocf_log err "CIDR Netmask not given"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
|
||||
if [[ -z $OCF_RESKEY_nic ]] ; then
|
||||
ocf_log err "Base NIC not given"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
|
||||
if [[ -z $OCF_RESKEY_base_veth ]] ; then
|
||||
ocf_log err "Base veth tail name not given"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
|
||||
if [[ -z $OCF_RESKEY_ns_veth ]] ; then
|
||||
ocf_log err "NS veth tail name not given"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
|
||||
if ! ocf_is_decimal "$OCF_RESKEY_gateway_metric"; then
|
||||
ocf_log err "Gateway_metric should be a positive digital value"
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
fi
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Find out which interfaces serve the given IP address and netmask.
|
||||
# The arguments are an IP address and a netmask.
|
||||
# Its output are interface names devided by spaces (e.g., "eth0 eth1").
|
||||
#
|
||||
find_interface() {
|
||||
local ipaddr="$1"
|
||||
local netmask="$2"
|
||||
[[ -z netmask ]] || ipaddr="$ipaddr/$netmask"
|
||||
|
||||
#
|
||||
# List interfaces but exclude FreeS/WAN ipsecN virtual interfaces
|
||||
local iface="`ip -o -f inet addr show \
|
||||
| grep "\ $ipaddr" \
|
||||
| cut -d ' ' -f2 \
|
||||
| grep -v '^ipsec[[0-9]][[0-9]]*$'`"
|
||||
local rc=$?
|
||||
echo "$iface"
|
||||
return $rc
|
||||
}
|
||||
|
||||
find_interface_in_ns() {
|
||||
local ns="$1"
|
||||
local ipaddr="$2"
|
||||
local netmask="$3"
|
||||
[[ -z netmask ]] || ipaddr="$ipaddr/$netmask"
|
||||
|
||||
#
|
||||
# List interfaces but exclude FreeS/WAN ipsecN virtual interfaces
|
||||
local iface=`ip netns exec $ns ip -o -f inet addr show \
|
||||
| grep "\ $ipaddr" \
|
||||
| cut -d ' ' -f2 \
|
||||
| grep -v '^ipsec[[0-9]][[0-9]]*$'`
|
||||
local rc=$?
|
||||
echo "$iface"
|
||||
return $rc
|
||||
}
|
||||
|
||||
setup_routes() {
|
||||
if [[ "${OCF_RESKEY_other_networks}" != "false" ]] ; then
|
||||
for network in ${OCF_RESKEY_other_networks}
|
||||
do
|
||||
ocf_log debug "Adding route on the host system to ${network}: ${OCF_RESKEY_namespace_ip}"
|
||||
ocf_run $RUN_IN_NS ip route add ${network} dev ${OCF_RESKEY_ns_veth}
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
setup_forwarding() {
|
||||
local forwarding
|
||||
local rc=$OCF_SUCCESS
|
||||
ocf_is_true ${OCF_RESKEY_enable_forwarding}
|
||||
if [[ $? == 0 ]] ; then
|
||||
ocf_run $RUN_IN_NS sysctl -w net.ipv4.ip_forward=1
|
||||
forwarding=$(cat /proc/sys/net/ipv4/ip_forward)
|
||||
if [[ "${forwarding}" != "1" ]] ; then
|
||||
ocf_run sysctl -w net.ipv4.ip_forward=1
|
||||
rc=$?
|
||||
fi
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
|
||||
add_to_bridge() {
|
||||
local bridge_mtu=`cat /sys/class/net/${OCF_RESKEY_bridge}/mtu`
|
||||
[ -d /sys/class/net/${OCF_RESKEY_bridge}/brif ]
|
||||
if [[ $? == 0 ]]; then
|
||||
ifconfig $OCF_RESKEY_base_veth mtu $bridge_mtu
|
||||
brctl addif $OCF_RESKEY_bridge $OCF_RESKEY_base_veth && ocf_run ifconfig $OCF_RESKEY_base_veth 0.0.0.0 || return $OCF_ERR_GENERIC
|
||||
else
|
||||
ovs-vsctl show | grep $OCF_RESKEY_ns_veth
|
||||
if [[ $? != 0 ]] ; then
|
||||
$RUN_IN_NS ifconfig $OCF_RESKEY_ns_veth mtu $bridge_mtu
|
||||
ocf_run ovs-vsctl add-port $OCF_RESKEY_bridge $OCF_RESKEY_ns_veth -- set Interface $OCF_RESKEY_ns_veth type=internal
|
||||
fi
|
||||
$RUN_IN_NS ip a | grep $OCF_RESKEY_ns_veth
|
||||
if [[ $? != 0 ]] ; then
|
||||
ocf_run ip link set $OCF_RESKEY_ns_veth netns $OCF_RESKEY_ns
|
||||
ocf_run $RUN_IN_NS ifconfig $OCF_RESKEY_ns_veth $OCF_RESKEY_ip/$OCF_RESKEY_cidr_netmask
|
||||
fi
|
||||
fi
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
remove_from_bridge() {
|
||||
[ -d /sys/class/net/${OCF_RESKEY_bridge}/brif ]
|
||||
if [[ $? == 0 ]]; then
|
||||
brctl delif $OCF_RESKEY_bridge $OCF_RESKEY_base_veth
|
||||
else
|
||||
ip netns exec network ifconfig $OCF_RESKEY_ns_veth 0.0.0.0
|
||||
fi
|
||||
}
|
||||
|
||||
get_first_ip_mask_for_if() {
|
||||
local iface="$1"
|
||||
local ns="$2"
|
||||
local RUN=''
|
||||
[[ -z ns ]] && RUN=$RUN_IN_NS
|
||||
local addr=`$RUN ip -o -f inet a show dev $iface \
|
||||
| sed -re '1!d; s|.*\s([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+).*|\1|'`
|
||||
local rc=$?
|
||||
[[ $rc != 0 ]] && addr=''
|
||||
echo "$addr"
|
||||
return $rc
|
||||
}
|
||||
|
||||
get_first_ip_for_if() {
|
||||
local iface="$1"
|
||||
local ns="$2"
|
||||
|
||||
local addr=`get_first_ip_mask_for_if $iface $ns \
|
||||
| sed -re 's|([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/.*|\1|'`
|
||||
local rc=$?
|
||||
[[ $rc != 0 ]] && addr=''
|
||||
echo "$addr"
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
||||
|
||||
check_ns() {
|
||||
local ns=`ip netns list | grep "$OCF_RESKEY_ns"`
|
||||
[[ $ns != $OCF_RESKEY_ns ]] && return $OCF_ERR_GENERIC
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
get_ns() {
|
||||
local rc
|
||||
check_ns && return $OCF_SUCCESS
|
||||
|
||||
ocf_run ip netns add $OCF_RESKEY_ns
|
||||
rc=$?
|
||||
ocf_run $RUN_IN_NS ip link set up dev lo
|
||||
|
||||
return $rc
|
||||
}
|
||||
|
||||
get_veth_pair() {
|
||||
local rc
|
||||
local rc1
|
||||
local ipaddr
|
||||
|
||||
# check tail of veth-pair in base system
|
||||
ocf_run ip link show $OCF_RESKEY_base_veth 2>/dev/null
|
||||
rc=$?
|
||||
|
||||
# create pair (tail's can't be alone) and attach tail to the net.namespace
|
||||
if [[ $rc != 0 ]] ; then
|
||||
ovs-vsctl show | grep $OCF_RESKEY_ns_veth
|
||||
rc1=$?
|
||||
if [[ $rc1 != 0 ]] ; then
|
||||
ocf_run ip link add $OCF_RESKEY_base_veth type veth peer name $OCF_RESKEY_ns_veth
|
||||
ocf_run ip link set dev $OCF_RESKEY_ns_veth netns $OCF_RESKEY_ns
|
||||
ocf_run $RUN_IN_NS ip link set up dev $OCF_RESKEY_ns_veth
|
||||
ocf_run ip link set up dev $OCF_RESKEY_base_veth
|
||||
sleep 1
|
||||
fi
|
||||
# duplicate first IP address from base iface to the veth
|
||||
if [[ -n $OCF_RESKEY_bridge ]] ; then
|
||||
ipaddr=`get_first_ip_mask_for_if $OCF_RESKEY_bridge`
|
||||
else
|
||||
ipaddr=`get_first_ip_mask_for_if $OCF_RESKEY_nic`
|
||||
fi
|
||||
[[ -z $ipaddr ]] && return 0 # dublicate nothing
|
||||
|
||||
if [[ $rc1 != 0 ]] ; then
|
||||
ocf_run ip addr add $ipaddr dev $OCF_RESKEY_base_veth
|
||||
fi
|
||||
|
||||
if [[ -z $OCF_RESKEY_bridge ]] ; then
|
||||
echo 1 > /proc/sys/net/ipv4/conf/$OCF_RESKEY_nic/proxy_arp
|
||||
echo 1 > /proc/sys/net/ipv4/conf/$OCF_RESKEY_base_veth/proxy_arp
|
||||
else
|
||||
add_to_bridge
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
check_interfaces_for_up_state() {
|
||||
local interfaces=$(echo "$1" | tr " ,:;" "\n")
|
||||
local rc=$OCF_SUCCESS
|
||||
|
||||
for i in $interfaces ; do
|
||||
rv=$(cat /sys/class/net/$i/carrier) # can return non-zero error-code for administrative-downed interface
|
||||
if [[ $? != 0 || $rv != "1" ]] ; then
|
||||
rc=$OCF_NOT_RUNNING
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
return $rc
|
||||
}
|
||||
|
||||
ip_prepare() {
|
||||
local rc
|
||||
ip_validate
|
||||
[[ $? != 0 ]] && return $OCF_ERR_GENERIC
|
||||
|
||||
# create or get existing network namespace
|
||||
get_ns || return $OCF_ERR_GENERIC
|
||||
|
||||
# create or get existing pair of veth interfaces
|
||||
get_veth_pair || return $OCF_ERR_GENERIC
|
||||
|
||||
# attach IP address inside network namespace
|
||||
ocf_run $RUN_IN_NS ip addr replace "$OCF_RESKEY_ip/$OCF_RESKEY_cidr_netmask" dev $OCF_RESKEY_ns_veth
|
||||
[[ $? != 0 ]] && return $OCF_ERR_GENERIC
|
||||
|
||||
# modify route in base system
|
||||
ovs-vsctl show | grep $OCF_RESKEY_ns_veth
|
||||
if [[ $? != 0 ]] ; then
|
||||
ocf_run ip route flush dev $OCF_RESKEY_base_veth
|
||||
[[ $? != 0 ]] && return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
if [[ -z $OCF_RESKEY_bridge ]] ; then
|
||||
ocf_run ip route add $OCF_RESKEY_ip dev $OCF_RESKEY_base_veth
|
||||
[[ $? != 0 ]] && return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
# setup default routing in namespace if gateway given
|
||||
if [[ $OCF_RESKEY_gateway == 'link' ]] ; then
|
||||
ocf_run $RUN_IN_NS ip route replace default dev $OCF_RESKEY_ns_veth metric $OCF_RESKEY_gateway_metric
|
||||
elif [[ $OCF_RESKEY_gateway == 'none' ]] ; then
|
||||
echo "Do nothing"
|
||||
else
|
||||
ocf_run $RUN_IN_NS ip route replace default via $OCF_RESKEY_gateway metric $OCF_RESKEY_gateway_metric
|
||||
fi
|
||||
ARGS="-i 200 -r 5 -p $SENDARPPIDFILE $OCF_RESKEY_nic $OCF_RESKEY_ip auto not_used not_used"
|
||||
($SENDARP $ARGS || ocf_log err "Could not send gratuitous arps")& >&2
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
iptables_start() {
|
||||
local rc
|
||||
local iptables_rules
|
||||
local ns_iptables_rules
|
||||
local rule
|
||||
rc=$OCF_SUCCESS
|
||||
# setup iptables rules if given
|
||||
if [[ $OCF_RESKEY_iptables_start_rules != "false" ]] ; then
|
||||
IFS=';' read -a iptables_rules <<< "$OCF_RESKEY_iptables_start_rules"
|
||||
for rule in "${iptables_rules[@]}"
|
||||
do
|
||||
ocf_run $rule -m comment --comment "$OCF_RESKEY_iptables_comment"
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ $OCF_RESKEY_ns_iptables_start_rules != "false" ]] ; then
|
||||
IFS=';' read -a ns_iptables_rules <<< "$OCF_RESKEY_ns_iptables_start_rules"
|
||||
for rule in "${ns_iptables_rules[@]}"
|
||||
do
|
||||
ocf_run ip netns exec $OCF_RESKEY_ns $rule
|
||||
done
|
||||
fi
|
||||
|
||||
setup_routes
|
||||
return $rc
|
||||
}
|
||||
|
||||
iptables_stop() {
|
||||
local rc
|
||||
local iptables_rules
|
||||
local ns_iptables_rules
|
||||
local rule
|
||||
rc=$OCF_SUCCESS
|
||||
# remove iptables rules if given
|
||||
if [[ $OCF_RESKEY_iptables_stop_rules != "false" ]] ; then
|
||||
IFS=';' read -a iptables_rules <<< "$OCF_RESKEY_iptables_stop_rules"
|
||||
for rule in "${iptables_rules[@]}"
|
||||
do
|
||||
ocf_run $rule -m comment --comment "$OCF_RESKEY_iptables_comment"
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ $OCF_RESKEY_ns_iptables_stop_rules != "false" ]] ; then
|
||||
IFS=';' read -a ns_iptables_rules <<< "$OCF_RESKEY_ns_iptables_stop_rules"
|
||||
for rule in "${ns_iptables_rules[@]}"
|
||||
do
|
||||
ocf_run ip netns exec $OCF_RESKEY_ns $rule
|
||||
done
|
||||
fi
|
||||
|
||||
return $rc
|
||||
}
|
||||
|
||||
ip_start() {
|
||||
setup_forwarding
|
||||
check_interfaces_for_up_state "$OCF_RESKEY_nic:$OCF_RESKEY_also_check_interfaces" || return $OCF_ERR_GENERIC
|
||||
ip_prepare
|
||||
|
||||
rc=$?
|
||||
if [[ $rc != $OCF_SUCCESS ]] ; then
|
||||
# cleanun ns
|
||||
ip_stop
|
||||
rc=$OCF_ERR_GENERIC
|
||||
else
|
||||
iptables_start
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
|
||||
ip_stop() {
|
||||
local rc
|
||||
ip_validate
|
||||
if [[ -n $OCF_RESKEY_bridge ]] ; then
|
||||
remove_from_bridge
|
||||
fi
|
||||
# destroy veth-pair in base system
|
||||
ocf_run ip link show $OCF_RESKEY_base_veth 2>/dev/null
|
||||
rc=$?
|
||||
if [[ $rc == 0 ]] ; then
|
||||
ocf_run ip link set down dev $OCF_RESKEY_base_veth &&
|
||||
sleep 2 && # prevent race
|
||||
ocf_run ip link del dev $OCF_RESKEY_base_veth
|
||||
rc=$?
|
||||
else
|
||||
rc=0
|
||||
fi
|
||||
|
||||
if [ -f "$SENDARPPIDFILE" ] ; then
|
||||
kill `cat "$SENDARPPIDFILE"`
|
||||
if [ $? -ne 0 ]; then
|
||||
ocf_log warn "Could not kill previously running send_arp for $OCF_RESKEY_ip"
|
||||
else
|
||||
ocf_log info "killed previously running send_arp for $OCF_RESKEY_ip"
|
||||
rm -f "$SENDARPPIDFILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [[ $rc == 0 ]] ; then
|
||||
rc=$OCF_SUCCESS # it means stop was success
|
||||
iptables_stop
|
||||
else
|
||||
rc=$OCF_ERR_GENERIC
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
|
||||
ip_monitor() {
|
||||
local rc
|
||||
ip_validate
|
||||
check_ns || return $OCF_NOT_RUNNING
|
||||
local iface=$(find_interface_in_ns $OCF_RESKEY_ns $OCF_RESKEY_ip $OCF_RESKEY_cidr_netmask)
|
||||
|
||||
[[ -z $iface ]] && return $OCF_NOT_RUNNING
|
||||
|
||||
#todo: finding IP from VIP subnet
|
||||
if [[ $OCF_RESKEY_bridge == false ]] ; then
|
||||
local ipaddr=$(get_first_ip_for_if $OCF_RESKEY_nic)
|
||||
else
|
||||
local ipaddr=$(get_first_ip_for_if $OCF_RESKEY_bridge)
|
||||
fi
|
||||
[[ -z $ipaddr ]] && return $OCF_NOT_RUNNING
|
||||
|
||||
check_interfaces_for_up_state "$OCF_RESKEY_nic:$OCF_RESKEY_also_check_interfaces" || return $OCF_NOT_RUNNING
|
||||
ocf_run $RUN_IN_NS ping -n -c3 -q $ipaddr 2>&1 >>/dev/null || return $OCF_NOT_RUNNING
|
||||
setup_forwarding
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
|
||||
ip_usage() {
|
||||
cat <<END
|
||||
usage: $0 {start|stop|status|monitor|validate-all|meta-data}
|
||||
|
||||
Expects to have a fully populated OCF RA-compliant environment set.
|
||||
END
|
||||
}
|
||||
|
||||
## main
|
||||
|
||||
rc=$OCF_SUCCESS
|
||||
case $__OCF_ACTION in
|
||||
meta-data)
|
||||
meta_data
|
||||
exit $OCF_SUCCESS
|
||||
;;
|
||||
usage|help)
|
||||
ip_usage
|
||||
exit $OCF_SUCCESS
|
||||
;;
|
||||
start)
|
||||
ip_start
|
||||
rc=$?
|
||||
;;
|
||||
stop)
|
||||
ip_stop
|
||||
rc=$?
|
||||
;;
|
||||
monitor)
|
||||
ip_monitor
|
||||
rc=$?
|
||||
;;
|
||||
validate-all)
|
||||
;;
|
||||
*)
|
||||
ip_usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED
|
||||
;;
|
||||
esac
|
||||
exit $rc
|
||||
# vi:sw=4:ts=8:
|
378
files/fuel-ha-utils/ocf/ns_conntrackd
Normal file
378
files/fuel-ha-utils/ocf/ns_conntrackd
Normal file
@ -0,0 +1,378 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
#
|
||||
# An OCF RA for conntrackd
|
||||
# http://conntrack-tools.netfilter.org/
|
||||
#
|
||||
# Copyright (c) 2011 Dominik Klein
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of version 2 of the GNU General Public License as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it would be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# Further, this software is distributed without any warranty that it is
|
||||
# free of the rightful claim of any third person regarding infringement
|
||||
# or the like. Any license provided herein, whether implied or
|
||||
# otherwise, applies only to this software file. Patent licenses, if
|
||||
# any, provided herein do not apply to combinations of this program with
|
||||
# other software, or any other product whatsoever.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
#
|
||||
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
#######################################################################
|
||||
|
||||
OCF_RESKEY_binary_default=conntrackd
|
||||
OCF_RESKEY_config_default=/etc/conntrackd/conntrackd.conf
|
||||
OCF_RESKEY_ns_default=vrouter
|
||||
OCF_RESKEY_bridge_default=br-mgmt
|
||||
OCF_RESKEY_host_interface_default=mgmt-conntrd
|
||||
OCF_RESKEY_ns_interface_default=conntrd
|
||||
|
||||
# For users of versions prior to 1.2:
|
||||
# Map renamed parameter "conntrackd" to "binary" if in use
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_conntrackd-${OCF_RESKEY_binary_default}}}
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_ns=${OCF_RESKEY_ns_default}}
|
||||
: ${OCF_RESKEY_bridge=${OCF_RESKEY_bridge_default}}
|
||||
: ${OCF_RESKEY_host_interface=${OCF_RESKEY_host_interface_default}}
|
||||
: ${OCF_RESKEY_ns_interface=${OCF_RESKEY_ns_interface_default}}
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="conntrackd">
|
||||
<version>1.2</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
Master/Slave OCF Resource Agent for conntrackd
|
||||
</longdesc>
|
||||
|
||||
<shortdesc lang="en">This resource agent manages conntrackd</shortdesc>
|
||||
|
||||
<parameters>
|
||||
<parameter name="binary">
|
||||
<longdesc lang="en">Name of the conntrackd executable.
|
||||
If conntrackd is installed and available in the default PATH, it is sufficient to configure the name of the binary
|
||||
For example "my-conntrackd-binary-version-0.9.14"
|
||||
If conntrackd is installed somewhere else, you may also give a full path
|
||||
For example "/packages/conntrackd-0.9.14/sbin/conntrackd"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Name of the conntrackd executable</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_binary_default"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="config">
|
||||
<longdesc lang="en">Full path to the conntrackd.conf file.
|
||||
For example "/packages/conntrackd-0.9.14/etc/conntrackd/conntrackd.conf"</longdesc>
|
||||
<shortdesc lang="en">Path to conntrackd.conf</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_config_default"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="30" />
|
||||
<action name="promote" timeout="30" />
|
||||
<action name="demote" timeout="30" />
|
||||
<action name="notify" timeout="30" />
|
||||
<action name="stop" timeout="30" />
|
||||
<action name="monitor" timeout="20" interval="20" role="Slave" />
|
||||
<action name="monitor" timeout="20" interval="10" role="Master" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
<action name="validate-all" timeout="30" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
meta_expect()
|
||||
{
|
||||
local what=$1 whatvar=OCF_RESKEY_CRM_meta_${1//-/_} op=$2 expect=$3
|
||||
local val=${!whatvar}
|
||||
if [[ -n $val ]]; then
|
||||
# [, not [[, or it won't work ;)
|
||||
[ $val $op $expect ] && return
|
||||
fi
|
||||
ocf_exit_reason "meta parameter misconfigured, expected $what $op $expect, but found ${val:-unset}."
|
||||
exit $OCF_ERR_CONFIGURED
|
||||
}
|
||||
|
||||
conntrackd_is_master() {
|
||||
# You can't query conntrackd whether it is master or slave. It can be both at the same time.
|
||||
# This RA creates a statefile during promote and enforces master-max=1 and clone-node-max=1
|
||||
ha_pseudo_resource $statefile monitor
|
||||
}
|
||||
|
||||
conntrackd_set_master_score() {
|
||||
${HA_SBIN_DIR}/crm_master -Q -l reboot -v $1
|
||||
}
|
||||
|
||||
add_to_bridge() {
|
||||
brctl show $OCF_RESKEY_bridge | grep $OCF_RESKEY_host_interface
|
||||
if [[ $rc != 0 ]] ; then
|
||||
ocf_run brctl addif $OCF_RESKEY_bridge $OCF_RESKEY_host_interface
|
||||
ocf_run ifconfig $OCF_RESKEY_host_interface 0.0.0.0
|
||||
fi
|
||||
}
|
||||
|
||||
get_veth_pair() {
|
||||
ip netns list | grep "$OCF_RESKEY_ns"
|
||||
|
||||
[[ $? != 0 ]] && ip netns add $OCF_RESKEY_ns && ip netns exec $OCF_RESKEY_ns ip link set up dev lo
|
||||
|
||||
ocf_run ip netns exec $OCF_RESKEY_ns ip link show $OCF_RESKEY_ns_interface 2>/dev/null
|
||||
rc=$?
|
||||
|
||||
# create pair (tail's can't be alone) and attach tail to the net.namespace
|
||||
if [[ $rc != 0 ]] ; then
|
||||
local last_octet=$(ifconfig $OCF_RESKEY_bridge 2>/dev/null|awk '/inet addr:/ {print $2}'|sed 's/addr://' | awk -F. '{print $NF}')
|
||||
|
||||
ocf_run ip link add $OCF_RESKEY_host_interface type veth peer name $OCF_RESKEY_ns_interface
|
||||
ocf_run ip link set dev $OCF_RESKEY_ns_interface netns $OCF_RESKEY_ns
|
||||
ocf_run ip netns exec $OCF_RESKEY_ns ip link set up dev $OCF_RESKEY_ns_interface
|
||||
ocf_run ip link set up dev $OCF_RESKEY_host_interface
|
||||
ocf_run ip netns exec $OCF_RESKEY_ns ifconfig $OCF_RESKEY_ns_interface 10.0.0.${last_octet}/24
|
||||
fi
|
||||
|
||||
add_to_bridge
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
conntrackd_monitor() {
|
||||
|
||||
get_veth_pair
|
||||
|
||||
rc=$OCF_NOT_RUNNING
|
||||
# It does not write a PID file, so check the socket exists after
|
||||
# extracting its path from the configuration file
|
||||
local conntrack_socket=$(awk '/^[ \t]*UNIX[ \t]*{/,/^[ \t]*}/ { if ($1 == "Path") { print $2 } }' $OCF_RESKEY_config)
|
||||
[ -S "$conntrack_socket" ] && rc=$OCF_SUCCESS
|
||||
if [ "$rc" -eq "$OCF_SUCCESS" ]; then
|
||||
# conntrackd is running
|
||||
# now see if it acceppts queries
|
||||
if ! ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -s > /dev/null 2>&1; then
|
||||
rc=$OCF_ERR_GENERIC
|
||||
ocf_exit_reason "conntrackd is running but not responding to queries"
|
||||
fi
|
||||
if conntrackd_is_master; then
|
||||
rc=$OCF_RUNNING_MASTER
|
||||
# Restore master setting on probes
|
||||
if [ $OCF_RESKEY_CRM_meta_interval -eq 0 ]; then
|
||||
conntrackd_set_master_score $master_score
|
||||
fi
|
||||
else
|
||||
# Restore master setting on probes
|
||||
if [ $OCF_RESKEY_CRM_meta_interval -eq 0 ]; then
|
||||
conntrackd_set_master_score $slave_score
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
|
||||
conntrackd_start() {
|
||||
rc=$OCF_ERR_GENERIC
|
||||
|
||||
# Keep trying to start the resource;
|
||||
# wait for the CRM to time us out if this fails
|
||||
while :; do
|
||||
conntrackd_monitor
|
||||
status=$?
|
||||
case "$status" in
|
||||
$OCF_SUCCESS)
|
||||
conntrackd_set_master_score $slave_score
|
||||
# -n = request resync from the others
|
||||
if ! ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -n; then
|
||||
ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -n failed during start."
|
||||
rc=$OCF_ERR_GENERIC
|
||||
else
|
||||
rc=$OCF_SUCCESS
|
||||
fi
|
||||
break
|
||||
;;
|
||||
$OCF_NOT_RUNNING)
|
||||
ocf_log info "Starting conntrackd"
|
||||
ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -d
|
||||
;;
|
||||
$OCF_RUNNING_MASTER)
|
||||
ocf_log warn "conntrackd already in master mode, demoting."
|
||||
ha_pseudo_resource $statefile stop
|
||||
;;
|
||||
$OCF_ERR_GENERIC)
|
||||
ocf_exit_reason "conntrackd start failed"
|
||||
rc=$OCF_ERR_GENERIC
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
return $rc
|
||||
}
|
||||
|
||||
conntrackd_stop() {
|
||||
rc=$OCF_ERR_GENERIC
|
||||
|
||||
# Keep trying to bring down the resource;
|
||||
# wait for the CRM to time us out if this fails
|
||||
while :; do
|
||||
conntrackd_monitor
|
||||
status=$?
|
||||
case "$status" in
|
||||
$OCF_SUCCESS|$OCF_ERR_GENERIC)
|
||||
ocf_log info "Stopping conntrackd"
|
||||
ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -k
|
||||
;;
|
||||
$OCF_NOT_RUNNING)
|
||||
rc=$OCF_SUCCESS
|
||||
break
|
||||
;;
|
||||
$OCF_RUNNING_MASTER)
|
||||
ocf_log warn "conntrackd still master"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
return $rc
|
||||
|
||||
}
|
||||
|
||||
conntrackd_validate_all() {
|
||||
check_binary "$OCF_RESKEY_binary"
|
||||
if ! [ -e "$OCF_RESKEY_config" ]; then
|
||||
ocf_exit_reason "Config FILE $OCF_RESKEY_config does not exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
meta_expect master-node-max = 1
|
||||
meta_expect master-max = 1
|
||||
meta_expect clone-node-max = 1
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
conntrackd_promote() {
|
||||
rc=$OCF_SUCCESS
|
||||
if ! conntrackd_is_master; then
|
||||
# -c = Commit the external cache to the kernel
|
||||
# -f = Flush internal and external cache
|
||||
# -R = resync with the kernel table
|
||||
# -B = send a bulk update on the line
|
||||
for parm in c f R B; do
|
||||
if ! ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm; then
|
||||
ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm failed during promote."
|
||||
rc=$OCF_ERR_GENERIC
|
||||
break
|
||||
fi
|
||||
done
|
||||
ha_pseudo_resource $statefile start
|
||||
conntrackd_set_master_score $master_score
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
|
||||
conntrackd_demote() {
|
||||
rc=$OCF_SUCCESS
|
||||
if conntrackd_is_master; then
|
||||
# -t = shorten kernel timers to remove zombies
|
||||
# -n = request a resync from the others
|
||||
for parm in t n; do
|
||||
if ! ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm; then
|
||||
ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm failed during demote."
|
||||
rc=$OCF_ERR_GENERIC
|
||||
break
|
||||
fi
|
||||
done
|
||||
ha_pseudo_resource $statefile stop
|
||||
conntrackd_set_master_score $slave_score
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
|
||||
conntrackd_notify() {
|
||||
hostname=$(hostname)
|
||||
# OCF_RESKEY_CRM_meta_notify_master_uname is a whitespace separated list of master hostnames
|
||||
for master in $OCF_RESKEY_CRM_meta_notify_master_uname; do
|
||||
# if we are the master and an instance was just started on another node:
|
||||
# send a bulk update to allow failback
|
||||
if [ "$hostname" = "$master" -a "$OCF_RESKEY_CRM_meta_notify_type" = "post" -a "$OCF_RESKEY_CRM_meta_notify_operation" = "start" -a "$OCF_RESKEY_CRM_meta_notify_start_uname" != "$hostname" ]; then
|
||||
ocf_log info "Sending bulk update in post start to peers to allow failback"
|
||||
ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -B
|
||||
fi
|
||||
done
|
||||
for tobepromoted in $OCF_RESKEY_CRM_meta_notify_promote_uname; do
|
||||
# if there is a promote action to be executed on another node:
|
||||
# send a bulk update to allow failback
|
||||
if [ "$hostname" != "$tobepromoted" -a "$OCF_RESKEY_CRM_meta_notify_type" = "pre" -a "$OCF_RESKEY_CRM_meta_notify_operation" = "promote" ]; then
|
||||
ocf_log info "Sending bulk update in pre promote to peers to allow failback"
|
||||
ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -B
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
conntrackd_usage() {
|
||||
cat <<EOF
|
||||
usage: $0 {start|stop|promote|demote|monitor|validate-all|meta-data}
|
||||
Expects to have a fully populated OCF RA-compliant environment set.
|
||||
EOF
|
||||
}
|
||||
|
||||
statefile=conntrackd.${OCF_RESOURCE_INSTANCE//:[0-9]*}.master
|
||||
|
||||
master_score=1000
|
||||
slave_score=100
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
conntrackd_usage
|
||||
exit $OCF_ERR_ARGS
|
||||
fi
|
||||
|
||||
case $__OCF_ACTION in
|
||||
meta-data)
|
||||
meta_data
|
||||
exit $OCF_SUCCESS
|
||||
;;
|
||||
usage)
|
||||
conntrackd_usage
|
||||
exit $OCF_SUCCESS
|
||||
esac
|
||||
|
||||
# Everything except usage and meta-data must pass the validate test
|
||||
conntrackd_validate_all || exit
|
||||
|
||||
case $__OCF_ACTION in
|
||||
start)
|
||||
conntrackd_start
|
||||
;;
|
||||
stop)
|
||||
conntrackd_stop
|
||||
;;
|
||||
promote)
|
||||
conntrackd_promote
|
||||
;;
|
||||
demote)
|
||||
conntrackd_demote
|
||||
;;
|
||||
status|monitor)
|
||||
conntrackd_monitor
|
||||
;;
|
||||
notify)
|
||||
conntrackd_notify
|
||||
;;
|
||||
validate-all)
|
||||
;;
|
||||
*)
|
||||
conntrackd_usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED
|
||||
esac
|
||||
# exit code is the exit code (return code) of the last command (shell function)
|
300
files/fuel-ha-utils/ocf/ns_dns
Normal file
300
files/fuel-ha-utils/ocf/ns_dns
Normal file
@ -0,0 +1,300 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Resource script for dnsmasq daemon with namespace support
|
||||
#
|
||||
# Description: Manages dnsmasq daemon as an OCF resource in
|
||||
# an High Availability setup inside a namespace
|
||||
#
|
||||
# HAProxy OCF script's Author: Mirantis
|
||||
# License: GNU General Public License (GPL)
|
||||
#
|
||||
# usage: $0 {start|stop|restart|status|monitor|validate-all|meta-data}
|
||||
#
|
||||
# The "start" arg starts dnsmasq.
|
||||
#
|
||||
# The "stop" arg stops it.
|
||||
#
|
||||
# OCF parameters:
|
||||
# OCF_RESKEY_ns
|
||||
# OCF_RESKEY_conffile
|
||||
# OCF_RESKEY_pidfile
|
||||
# OCF_RESKEY_binpath
|
||||
# OCF_RESKEY_extraconf
|
||||
#
|
||||
# Note: This RA requires that the dnsmasq config files has a "pidfile"
|
||||
# entry so that it is able to act on the correct process
|
||||
##########################################################################
|
||||
# Initialization:
|
||||
|
||||
OCF_ROOT_default="/usr/lib/ocf"
|
||||
|
||||
OCF_RESKEY_ns_default="haproxy"
|
||||
OCF_RESKEY_conffile_default="/etc/dnsmasq.d/dns.conf"
|
||||
OCF_RESKEY_pidfile_default="/var/run/dnsmasq.pid"
|
||||
OCF_RESKEY_binpath_default="/usr/sbin/dnsmasq"
|
||||
OCF_RESKEY_extraconf_default=""
|
||||
|
||||
: ${OCF_ROOT=${OCF_ROOT_default}}
|
||||
|
||||
: ${OCF_RESKEY_ns=${OCF_RESKEY_ns_default}}
|
||||
: ${OCF_RESKEY_conffile=${OCF_RESKEY_conffile_default}}
|
||||
: ${OCF_RESKEY_pidfile=${OCF_RESKEY_pidfile_default}}
|
||||
: ${OCF_RESKEY_binpath=${OCF_RESKEY_binpath_default}}
|
||||
: ${OCF_RESKEY_extraconf=${OCF_RESKEY_extraconf_default}}
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs
|
||||
|
||||
USAGE="Usage: $0 {start|stop|restart|status|monitor|validate-all|meta-data}";
|
||||
|
||||
RUN_IN_NS="ip netns exec $OCF_RESKEY_ns "
|
||||
if [[ -z $OCF_RESKEY_ns ]] ; then
|
||||
RUN=''
|
||||
else
|
||||
RUN="$RUN_IN_NS "
|
||||
fi
|
||||
|
||||
##########################################################################
|
||||
|
||||
usage()
|
||||
{
|
||||
echo $USAGE >&2
|
||||
}
|
||||
|
||||
meta_data()
|
||||
{
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="dnsmasq">
|
||||
<version>1.0</version>
|
||||
<longdesc lang="en">
|
||||
This script manages dnsmasq daemon with namespace support
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages an dnsmasq daemon inside a namespace</shortdesc>
|
||||
|
||||
<parameters>
|
||||
|
||||
<parameter name="ns">
|
||||
<longdesc lang="en">
|
||||
Name of network namespace.
|
||||
Should be present.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Name of network namespace.</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_ns_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="conffile">
|
||||
<longdesc lang="en">
|
||||
The dnsmasq daemon configuration file name with full path.
|
||||
For example, "/etc/dnsmasq/dnsmasq.cfg"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Configuration file name with full path</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_conffile_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pidfile">
|
||||
<longdesc lang="en">
|
||||
The dnsmasq pid file path.
|
||||
For example, "/var/run/dnsmasq.pid"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Full path to the dnsmasq pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pidfile_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="binpath">
|
||||
<longdesc lang="en">
|
||||
The dnsmasq binary path.
|
||||
For example, "/usr/sbin/dnsmasq"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Full path to the dnsmasq binary</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binpath_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="extraconf">
|
||||
<longdesc lang="en">
|
||||
Extra command line arguments to pass to dnsmasq.
|
||||
For example, "-f /etc/dnsmasq/shared.cfg"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Extra command line arguments for dnsmasq</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_extraconf_default}" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20s"/>
|
||||
<action name="stop" timeout="20s"/>
|
||||
<action name="monitor" depth="0" timeout="20s" interval="60s" />
|
||||
<action name="validate-all" timeout="20s"/>
|
||||
<action name="meta-data" timeout="5s"/>
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
exit $OCF_SUCCESS
|
||||
}
|
||||
|
||||
check_ns() {
|
||||
local ns=`ip netns list | grep "$OCF_RESKEY_ns"`
|
||||
[[ $ns != $OCF_RESKEY_ns ]] && return $OCF_ERR_GENERIC
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
get_ns() {
|
||||
local rc
|
||||
check_ns && return $OCF_SUCCESS
|
||||
|
||||
ocf_run ip netns add $OCF_RESKEY_ns
|
||||
rc=$?
|
||||
ocf_run $RUN_IN_NS ip link set up dev lo
|
||||
|
||||
return $rc
|
||||
}
|
||||
|
||||
get_variables() {
|
||||
get_ns
|
||||
CONF_FILE="${OCF_RESKEY_conffile}"
|
||||
COMMAND="$RUN ${OCF_RESKEY_binpath}"
|
||||
PIDFILE="${OCF_RESKEY_pidfile}"
|
||||
}
|
||||
|
||||
dnsmasq_status() {
|
||||
get_variables
|
||||
if [ -n "${PIDFILE}" -a -f "${PIDFILE}" ]; then
|
||||
# dnsmasq is probably running
|
||||
# get pid from pidfile
|
||||
PID="`cat ${PIDFILE}`"
|
||||
if [ -n "${PID}" ]; then
|
||||
# check if process exists
|
||||
if $RUN ps -p "${PID}" | grep -q dnsmasq; then
|
||||
ocf_log info "dnsmasq daemon running"
|
||||
return $OCF_SUCCESS
|
||||
else
|
||||
ocf_log info "dnsmasq daemon is not running but pid file exists"
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
else
|
||||
ocf_log err "PID file empty!"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
# dnsmasq is not running
|
||||
ocf_log info "dnsmasq daemon is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
}
|
||||
|
||||
dnsmasq_start()
|
||||
{
|
||||
get_variables
|
||||
# if dnsmasq is running return success
|
||||
dnsmasq_status
|
||||
retVal=$?
|
||||
if [ $retVal -eq $OCF_SUCCESS ]; then
|
||||
return $OCF_SUCCESS
|
||||
elif [ $retVal -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "Error. Unknown status."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
# run the dnsmasq binary
|
||||
ocf_run ${COMMAND} ${OCF_RESKEY_extraconf} --conf-file=${CONF_FILE} --pid-file="${PIDFILE}"
|
||||
if [ $? -ne 0 ]; then
|
||||
ocf_log err "Error. dnsmasq daemon returned error $?."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
ocf_log info "Started dnsmasq daemon."
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
dnsmasq_stop()
|
||||
{
|
||||
get_variables
|
||||
if dnsmasq_status ; then
|
||||
PID="`${RUN} cat ${PIDFILE}`"
|
||||
if [ -n "${PID}" ] ; then
|
||||
kill "${PID}"
|
||||
if [ $? -ne 0 ]; then
|
||||
kill -SIGKILL "${PID}"
|
||||
if [ $? -ne 0 ]; then
|
||||
ocf_log err "Error. Could not stop dnsmasq daemon."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
rm -f "${PIDFILE}"
|
||||
fi
|
||||
fi
|
||||
ocf_log info "Stopped dnsmasq daemon."
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
dnsmasq_monitor()
|
||||
{
|
||||
dnsmasq_status
|
||||
}
|
||||
|
||||
dnsmasq_validate_all()
|
||||
{
|
||||
get_variables
|
||||
if [ -n "$OCF_RESKEY_binpath" -a ! -x "$OCF_RESKEY_binpath" ]; then
|
||||
ocf_log err "Binary path $OCF_RESKEY_binpath does not exist."
|
||||
return $OCF_ERR_ARGS
|
||||
fi
|
||||
if [ -n "$OCF_RESKEY_conffile" -a ! -f "$OCF_RESKEY_conffile" ]; then
|
||||
ocf_log err "Config file $OCF_RESKEY_conffile does not exist."
|
||||
return $OCF_ERR_ARGS
|
||||
fi
|
||||
|
||||
if grep -v "^#" "$CONF_FILE" | grep "pidfile" > /dev/null ; then
|
||||
:
|
||||
else
|
||||
ocf_log err "Error. \"pidfile\" entry required in the dnsmasq config file by dnsmasq OCF RA."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
dnsmasq_restart()
|
||||
{
|
||||
dnsmasq_stop
|
||||
dnsmasq_start
|
||||
}
|
||||
|
||||
#
|
||||
# Main
|
||||
#
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
usage
|
||||
exit $OCF_ERR_ARGS
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
start) dnsmasq_start
|
||||
;;
|
||||
|
||||
stop) dnsmasq_stop
|
||||
;;
|
||||
|
||||
restart) dnsmasq_restart
|
||||
;;
|
||||
|
||||
status) dnsmasq_status
|
||||
;;
|
||||
|
||||
monitor) dnsmasq_monitor
|
||||
;;
|
||||
|
||||
validate-all) dnsmasq_validate_all
|
||||
;;
|
||||
|
||||
meta-data) meta_data
|
||||
;;
|
||||
|
||||
usage) usage; exit $OCF_SUCCESS
|
||||
;;
|
||||
|
||||
*) usage; exit $OCF_ERR_UNIMPLEMENTED
|
||||
;;
|
||||
esac
|
555
files/fuel-ha-utils/ocf/ns_haproxy
Executable file
555
files/fuel-ha-utils/ocf/ns_haproxy
Executable file
@ -0,0 +1,555 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Resource script for haproxy daemon with namespace support
|
||||
#
|
||||
# Description: Manages haproxy daemon as an OCF resource in
|
||||
# an High Availability setup inside a namespace
|
||||
#
|
||||
# HAProxy OCF script's Author: Mirantis
|
||||
# License: GNU General Public License (GPL)
|
||||
#
|
||||
# usage: $0 {start|stop|restart|status|monitor|validate-all|meta-data}
|
||||
#
|
||||
# The "start" arg starts haproxy.
|
||||
#
|
||||
# The "stop" arg stops it.
|
||||
#
|
||||
# OCF parameters:
|
||||
# OCF_RESKEY_ns
|
||||
# OCF_RESKEY_conffile
|
||||
# OCF_RESKEY_pidfile
|
||||
# OCF_RESKEY_binpath
|
||||
# OCF_RESKEY_extraconf
|
||||
#
|
||||
# OCF_RESKEY_host_interface
|
||||
# OCF_RESKEY_namespace_interface
|
||||
# OCF_RESKEY_host_ip
|
||||
# OCF_RESKEY_namespace_ip
|
||||
# OCF_RESKEY_network_mask
|
||||
# OCF_RESKEY_route_metric
|
||||
#
|
||||
# Note: This RA requires that the haproxy config files has a "pidfile"
|
||||
# entry so that it is able to act on the correct process
|
||||
##########################################################################
|
||||
# Initialization:
|
||||
|
||||
OCF_ROOT_default="/usr/lib/ocf"
|
||||
|
||||
OCF_RESKEY_ns_default="haproxy"
|
||||
OCF_RESKEY_conffile_default="/etc/haproxy/haproxy.cfg"
|
||||
OCF_RESKEY_pidfile_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
OCF_RESKEY_binpath_default="/usr/sbin/haproxy"
|
||||
OCF_RESKEY_extraconf_default=""
|
||||
|
||||
OCF_RESKEY_other_networks_default=""
|
||||
OCF_RESKEY_host_interface_default="hapr-host"
|
||||
OCF_RESKEY_namespace_interface_default="hapr-ns"
|
||||
OCF_RESKEY_host_ip_default="240.0.0.1"
|
||||
OCF_RESKEY_namespace_ip_default="240.0.0.2"
|
||||
OCF_RESKEY_network_mask_default="30"
|
||||
OCF_RESKEY_route_metric_default="10000"
|
||||
OCF_RESKEY_debug_default=false
|
||||
|
||||
: ${OCF_ROOT=${OCF_ROOT_default}}
|
||||
|
||||
: ${OCF_RESKEY_ns=${OCF_RESKEY_ns_default}}
|
||||
: ${OCF_RESKEY_conffile=${OCF_RESKEY_conffile_default}}
|
||||
: ${OCF_RESKEY_pidfile=${OCF_RESKEY_pidfile_default}}
|
||||
: ${OCF_RESKEY_binpath=${OCF_RESKEY_binpath_default}}
|
||||
: ${OCF_RESKEY_extraconf=${OCF_RESKEY_extraconf_default}}
|
||||
|
||||
: ${OCF_RESKEY_other_networks=${OCF_RESKEY_other_networks_default}}
|
||||
: ${OCF_RESKEY_host_interface=${OCF_RESKEY_host_interface_default}}
|
||||
: ${OCF_RESKEY_namespace_interface=${OCF_RESKEY_namespace_interface_default}}
|
||||
: ${OCF_RESKEY_host_ip=${OCF_RESKEY_host_ip_default}}
|
||||
: ${OCF_RESKEY_namespace_ip=${OCF_RESKEY_namespace_ip_default}}
|
||||
: ${OCF_RESKEY_network_mask=${OCF_RESKEY_network_mask_default}}
|
||||
: ${OCF_RESKEY_route_metric=${OCF_RESKEY_route_metric_default}}
|
||||
: ${OCF_RESKEY_debug=${OCF_RESKEY_debug_default}}
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs
|
||||
|
||||
USAGE="Usage: $0 {start|stop|restart|status|monitor|validate-all|meta-data}";
|
||||
|
||||
RUN_IN_NS="ip netns exec $OCF_RESKEY_ns "
|
||||
if [[ -z $OCF_RESKEY_ns ]] ; then
|
||||
RUN=''
|
||||
else
|
||||
RUN="$RUN_IN_NS "
|
||||
fi
|
||||
|
||||
##########################################################################
|
||||
|
||||
usage()
|
||||
{
|
||||
echo $USAGE >&2
|
||||
}
|
||||
|
||||
meta_data()
|
||||
{
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="haproxy">
|
||||
<version>1.0</version>
|
||||
<longdesc lang="en">
|
||||
This script manages haproxy daemon with namespace support
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages an haproxy daemon inside an namespace</shortdesc>
|
||||
|
||||
<parameters>
|
||||
|
||||
<parameter name="ns">
|
||||
<longdesc lang="en">
|
||||
Name of network namespace.
|
||||
Should be present.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Name of network namespace.</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_ns_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="conffile">
|
||||
<longdesc lang="en">
|
||||
The haproxy daemon configuration file name with full path.
|
||||
For example, "/etc/haproxy/haproxy.cfg"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Configuration file name with full path</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_conffile_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pidfile">
|
||||
<longdesc lang="en">
|
||||
The haproxy pid file path.
|
||||
For example, "/var/run/haproxy.pid"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Full path to the haproxy pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pidfile_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="binpath">
|
||||
<longdesc lang="en">
|
||||
The haproxy binary path.
|
||||
For example, "/usr/sbin/haproxy"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Full path to the haproxy binary</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binpath_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="extraconf">
|
||||
<longdesc lang="en">
|
||||
Extra command line arguments to pass to haproxy.
|
||||
For example, "-f /etc/haproxy/shared.cfg"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Extra command line arguments for haproxy</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_extraconf_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="other_networks">
|
||||
<longdesc lang="en">
|
||||
Additional routes that should be added to this resource. Routes will be added via value namespace_interface.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">List of addtional routes to add routes for.</shortdesc>
|
||||
<content type="string" default="$OCF_RESKEY_other_networks_default"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="host_interface">
|
||||
<longdesc lang="en">
|
||||
The host part of the interface pair used to connect the namespace to the network
|
||||
For example, "hapr-host"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">The name of the host interface used for namespace</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_host_interface_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="namespace_interface">
|
||||
<longdesc lang="en">
|
||||
The namespace part of the interface pair used to connect the namespace to the network
|
||||
For example, "hapr-ns"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">The name of the namespace interface used for namespace</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_namespace_interface_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="host_ip">
|
||||
<longdesc lang="en">
|
||||
The IP address used by the host interface. Must be from the same subnet as namesapce IP
|
||||
and uses network_mask to determine subnet.
|
||||
Should not collide with any IP addresses already used in your network.
|
||||
For example, "240.0.0.1"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Host interface IP address</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_host_ip_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="namespace_ip">
|
||||
<longdesc lang="en">
|
||||
The IP address used by the namespace interface. Must be from the same subnet as host IP
|
||||
and uses network_mask to determine subnet.
|
||||
Should not collide with any IP addresses already used in your network.
|
||||
For example, "240.0.0.2"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Namespace interface IP address</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_namespace_ip_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="network_mask">
|
||||
<longdesc lang="en">
|
||||
The network mask length used to determine subnet of the host
|
||||
and the namspace interfaces.
|
||||
For example, "30"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Network mask length</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_network_mask_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="route_metric">
|
||||
<longdesc lang="en">
|
||||
The metric value of the default route set for the pipe
|
||||
link connecting namespace and host. It should be set to
|
||||
a large number to be higher then other default route metrics
|
||||
that could be set to override this default route.
|
||||
If other routes are set eithin the namespace thir metric should
|
||||
be smaller then this number if you want them to be used istead of
|
||||
this route.
|
||||
For example, "1000"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Namespace default route metric</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_route_metric_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="debug" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The debug flag for haproxy.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">HAProxy RA debug flag</shortdesc>
|
||||
<content type="boolean" default="${OCF_RESKEY_debug_default}" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20s"/>
|
||||
<action name="stop" timeout="20s"/>
|
||||
<action name="reload" timeout="20s"/>
|
||||
<action name="monitor" depth="0" timeout="20s" interval="60s" />
|
||||
<action name="validate-all" timeout="20s"/>
|
||||
<action name="meta-data" timeout="5s"/>
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
exit $OCF_SUCCESS
|
||||
}
|
||||
|
||||
check_ns() {
|
||||
local LH="${LL} check_ns():"
|
||||
local ns=`ip netns list | grep "$OCF_RESKEY_ns"`
|
||||
ocf_log debug "${LH} recieved netns list: ${ns}"
|
||||
[[ $ns != $OCF_RESKEY_ns ]] && return $OCF_ERR_GENERIC
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
get_ns() {
|
||||
local rc
|
||||
local LH="${LL} get_ns():"
|
||||
check_ns && return $OCF_SUCCESS
|
||||
|
||||
ocf_run ip netns add $OCF_RESKEY_ns
|
||||
rc=$?
|
||||
ocf_run $RUN_IN_NS ip link set up dev lo
|
||||
ocf_log debug "${LH} added netns ${OCF_RESKEY_ns} and set up lo"
|
||||
|
||||
return $rc
|
||||
}
|
||||
|
||||
get_variables() {
|
||||
local LH="${LL} get_variables():"
|
||||
get_ns
|
||||
CONF_FILE="${OCF_RESKEY_conffile}"
|
||||
COMMAND="$RUN ${OCF_RESKEY_binpath}"
|
||||
if [ -n "${OCF_RESKEY_pidfile}" ]; then
|
||||
PIDFILE=$(grep -v "#" ${CONF_FILE} | grep "pidfile" | sed 's/^[ \t]*pidfile[ \t]*//')
|
||||
else
|
||||
PIDFILE="${OCF_RESKEY_pidfile}"
|
||||
fi
|
||||
ocf_log debug "${LH} set up variables and PIDFILE name"
|
||||
}
|
||||
|
||||
set_ns_routing() {
|
||||
|
||||
nsip() {
|
||||
ip netns exec "${OCF_RESKEY_ns}" ip ${@}
|
||||
}
|
||||
|
||||
# create host-ns veth pair unless it's present
|
||||
ip link | grep -q -w "${OCF_RESKEY_host_interface}:"
|
||||
if [ $? -gt 0 ]; then
|
||||
ocf_log debug "Creating host interface: ${OCF_RESKEY_host_interface} and namespace interface: ${OCF_RESKEY_namespace_interface}"
|
||||
ocf_run ip link add "${OCF_RESKEY_host_interface}" type veth peer name "${OCF_RESKEY_namespace_interface}"
|
||||
fi
|
||||
|
||||
# move the ns part to the namespace
|
||||
ip link | grep -q -w "${OCF_RESKEY_namespace_interface}:"
|
||||
if [ $? -eq 0 ]; then
|
||||
ocf_log debug "Moving interface: ${OCF_RESKEY_namespace_interface} to namespace: ${OCF_RESKEY_ns}"
|
||||
ocf_run ip link set dev "${OCF_RESKEY_namespace_interface}" netns "${OCF_RESKEY_ns}"
|
||||
fi
|
||||
|
||||
# up the host part
|
||||
ocf_log debug "Bringing up host interface: ${OCF_RESKEY_host_interface}"
|
||||
ocf_run ip link set "${OCF_RESKEY_host_interface}" up
|
||||
|
||||
# set host part's ip
|
||||
ip addr show dev "${OCF_RESKEY_host_interface}" | grep -q "inet ${OCF_RESKEY_host_ip}/${OCF_RESKEY_network_mask}"
|
||||
if [ $? -gt 0 ]; then
|
||||
ocf_log debug "Setting host interface: ${OCF_RESKEY_host_interface} IP to: ${OCF_RESKEY_host_ip}/${OCF_RESKEY_network_mask}"
|
||||
ocf_run ip addr add "${OCF_RESKEY_host_ip}/${OCF_RESKEY_network_mask}" dev "${OCF_RESKEY_host_interface}"
|
||||
fi
|
||||
|
||||
# up the ns part
|
||||
ocf_log debug "Bringing up the namespace interface: ${OCF_RESKEY_namespace_interface}"
|
||||
ocf_run nsip link set "${OCF_RESKEY_namespace_interface}" up
|
||||
|
||||
# set ns part's ip
|
||||
nsip addr show dev "${OCF_RESKEY_namespace_interface}" | grep -q "inet ${OCF_RESKEY_namespace_ip}/${OCF_RESKEY_network_mask}"
|
||||
if [ $? -gt 0 ]; then
|
||||
ocf_log debug "Setting namespace interface: ${OCF_RESKEY_namespace_interface} IP to: ${OCF_RESKEY_namespace_ip}/${OCF_RESKEY_network_mask}"
|
||||
ocf_run nsip addr add "${OCF_RESKEY_namespace_ip}/${OCF_RESKEY_network_mask}" dev "${OCF_RESKEY_namespace_interface}"
|
||||
fi
|
||||
|
||||
# set default gateway inside ns
|
||||
nsip route list | grep -q "default via ${OCF_RESKEY_host_ip}"
|
||||
if [ $? -gt 0 ]; then
|
||||
ocf_log debug "Creating default route inside the namespace to ${OCF_RESKEY_host_ip} with metric ${OCF_RESKEY_route_metric}"
|
||||
ocf_run nsip route add default via "${OCF_RESKEY_host_ip}" metric "${OCF_RESKEY_route_metric}"
|
||||
fi
|
||||
|
||||
# set masquerade on host node
|
||||
iptables -t nat -L | grep -q masquerade-for-haproxy-namespace
|
||||
if [ $? -gt 0 ]; then
|
||||
ocf_log debug "Creating NAT rule on the host system for traffic from IP: ${OCF_RESKEY_namespace_ip}"
|
||||
ocf_run iptables -t nat -A POSTROUTING -s "${OCF_RESKEY_namespace_ip}" -j MASQUERADE -m comment --comment "masquerade-for-haproxy-namespace"
|
||||
fi
|
||||
|
||||
if [[ "${OCF_RESKEY_other_networks}" != "false" ]] ; then
|
||||
for network in ${OCF_RESKEY_other_networks}
|
||||
do
|
||||
ocf_log debug "Adding route on the host system to ${network}: ${OCF_RESKEY_namespace_ip}"
|
||||
ocf_run $RUN_IN_NS ip route replace ${network} via ${OCF_RESKEY_host_ip} metric 10000
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
haproxy_status() {
|
||||
get_variables
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${PIDFILE} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
ocf_log debug "Create pid file dir: ${PID_DIR}"
|
||||
mkdir -p "${PID_DIR}"
|
||||
# no need to chown, root is user for haproxy
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
if [ -n "${PIDFILE}" -a -f "${PIDFILE}" ]; then
|
||||
# haproxy is probably running
|
||||
# get pid from pidfile
|
||||
PID="`cat ${PIDFILE}`"
|
||||
if [ -n "${PID}" ]; then
|
||||
# check if process exists
|
||||
if $RUN ps -p "${PID}" | grep -q haproxy; then
|
||||
ocf_log info "haproxy daemon running"
|
||||
return $OCF_SUCCESS
|
||||
else
|
||||
ocf_log warn "haproxy daemon is not running but pid file exists"
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
else
|
||||
ocf_log err "PID file empty!"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
# haproxy is not running
|
||||
ocf_log info "haproxy daemon is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
}
|
||||
|
||||
haproxy_start()
|
||||
{
|
||||
get_variables
|
||||
|
||||
# if haproxy is running return success
|
||||
haproxy_status
|
||||
retVal=$?
|
||||
if [ $retVal -eq $OCF_SUCCESS ]; then
|
||||
return $OCF_SUCCESS
|
||||
elif [ $retVal -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "Error. Unknown status."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
# run the haproxy binary
|
||||
ocf_run ${COMMAND} ${OCF_RESKEY_extraconf} -f "${CONF_FILE}" -p "${PIDFILE}"
|
||||
if [ $? -ne 0 ]; then
|
||||
ocf_log err "Error. haproxy daemon returned error $?."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
if [ "${OCF_RESKEY_ns}" != '' ]; then
|
||||
set_ns_routing
|
||||
fi
|
||||
|
||||
ocf_log info "Started haproxy daemon."
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
haproxy_reload()
|
||||
{
|
||||
get_variables
|
||||
if haproxy_status; then
|
||||
# get pid from pidfile
|
||||
PID="`cat ${PIDFILE}`"
|
||||
# reload haproxy binary replacing the old process
|
||||
ocf_run ${COMMAND} ${OCF_RESKEY_extraconf} -f "${CONF_FILE}" -p "${PIDFILE}" -sf "${PID}"
|
||||
if [ $? -ne 0 ]; then
|
||||
ocf_log err "Error. haproxy daemon returned error $?."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
else
|
||||
ocf_log info "Haproxy daemon is not running. Starting it."
|
||||
haproxy_start
|
||||
fi
|
||||
}
|
||||
|
||||
# Try to kill (SIGTERM) specified pid 5 times by 2 sec interval
|
||||
haproxy_kill()
|
||||
{
|
||||
local rc
|
||||
local PID="$1"
|
||||
local count=5
|
||||
local LH="${LL} haproxy_kill():"
|
||||
|
||||
while [ $count -gt 0 ]; do
|
||||
if [ -d /proc/${PID}/ ] ; then
|
||||
ocf_log debug "${LH} Stopping haproxy daemon with SIGTERM... "
|
||||
ocf_run kill "${PID}"
|
||||
rc=$?
|
||||
if [ $rc -eq 0 -a ! -d /proc/${PID}/ ]; then
|
||||
ocf_log debug "${LH} Stopped haproxy daemon with SIGTERM"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
sleep 2
|
||||
count=$(( count-1 ))
|
||||
done
|
||||
ocf_log debug "${LH} Failed to stop haproxy daemon with SIGTERM"
|
||||
return 1
|
||||
}
|
||||
|
||||
haproxy_stop()
|
||||
{
|
||||
local rc
|
||||
local LH="${LL} haproxy_stop():"
|
||||
get_variables
|
||||
if haproxy_status ; then
|
||||
PID="`${RUN} cat ${PIDFILE}`"
|
||||
if [ -z "${PID}" -o "${PID}" -eq "1" -o ! -d /proc/${PID}/ ]; then
|
||||
ocf_log err "${LH} Cannot stop haproxy (PID=${PID})"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
haproxy_kill "${PID}"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 -a -d /proc/${PID}/ ]; then
|
||||
ocf_run kill -SIGKILL "${PID}"
|
||||
ocf_log err "${LH} Failed to stop haproxy daemon gracefully. Killed with SIGKILL"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "${LH} Error. Could not stop haproxy daemon."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
ocf_log debug "Delete pid file: ${PIDFILE} with content ${PID}"
|
||||
rm -f "${PIDFILE}"
|
||||
fi
|
||||
ocf_log info "Stopped haproxy daemon."
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
haproxy_monitor()
|
||||
{
|
||||
haproxy_status
|
||||
}
|
||||
|
||||
haproxy_validate_all()
|
||||
{
|
||||
get_variables
|
||||
if [ -n "$OCF_RESKEY_binpath" -a ! -x "$OCF_RESKEY_binpath" ]; then
|
||||
ocf_log err "Binary path $OCF_RESKEY_binpath does not exist."
|
||||
return $OCF_ERR_ARGS
|
||||
fi
|
||||
if [ -n "$OCF_RESKEY_conffile" -a ! -f "$OCF_RESKEY_conffile" ]; then
|
||||
ocf_log err "Config file $OCF_RESKEY_conffile does not exist."
|
||||
return $OCF_ERR_ARGS
|
||||
fi
|
||||
|
||||
if grep -v "^#" "$CONF_FILE" | grep "pidfile" > /dev/null ; then
|
||||
:
|
||||
else
|
||||
ocf_log err "Error. \"pidfile\" entry required in the haproxy config file by haproxy OCF RA."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
haproxy_restart()
|
||||
{
|
||||
haproxy_stop
|
||||
haproxy_start
|
||||
}
|
||||
|
||||
#
|
||||
# Main
|
||||
#
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
usage
|
||||
exit $OCF_ERR_ARGS
|
||||
fi
|
||||
umask 0022
|
||||
export LL="${OCF_RESOURCE_INSTANCE}:"
|
||||
|
||||
case $1 in
|
||||
start) haproxy_start
|
||||
;;
|
||||
|
||||
stop) haproxy_stop
|
||||
;;
|
||||
|
||||
reload) haproxy_reload
|
||||
;;
|
||||
|
||||
restart) haproxy_restart
|
||||
;;
|
||||
|
||||
status) haproxy_status
|
||||
;;
|
||||
|
||||
monitor) haproxy_monitor
|
||||
;;
|
||||
|
||||
validate-all) haproxy_validate_all
|
||||
;;
|
||||
|
||||
meta-data) meta_data
|
||||
;;
|
||||
|
||||
usage) usage; exit $OCF_SUCCESS
|
||||
;;
|
||||
|
||||
*) usage; exit $OCF_ERR_UNIMPLEMENTED
|
||||
;;
|
||||
esac
|
440
files/fuel-ha-utils/ocf/ns_ntp
Normal file
440
files/fuel-ha-utils/ocf/ns_ntp
Normal file
@ -0,0 +1,440 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Resource script for ntp daemon with namespace support
|
||||
#
|
||||
# Description: Manages ntp daemon as an OCF resource in
|
||||
# an High Availability setup inside a namespace
|
||||
#
|
||||
# HAProxy OCF script's Author: Mirantis
|
||||
# License: GNU General Public License (GPL)
|
||||
#
|
||||
# usage: $0 {start|stop|restart|status|monitor|validate-all|meta-data}
|
||||
#
|
||||
# The "start" arg starts ntp.
|
||||
#
|
||||
# The "stop" arg stops it.
|
||||
#
|
||||
# OCF parameters:
|
||||
# OCF_RESKEY_ns
|
||||
# OCF_RESKEY_conffile
|
||||
# OCF_RESKEY_pidfile
|
||||
# OCF_RESKEY_binpath
|
||||
# OCF_RESKEY_extraconf
|
||||
#
|
||||
# Note: This RA requires that the ntp config files has a "pidfile"
|
||||
# entry so that it is able to act on the correct process
|
||||
##########################################################################
|
||||
# Initialization:
|
||||
|
||||
OCF_ROOT_default="/usr/lib/ocf"
|
||||
|
||||
OCF_RESKEY_ns_default="vrouter"
|
||||
OCF_RESKEY_conffile_default="/etc/ntp.conf"
|
||||
OCF_RESKEY_pidfile_default="/var/run/ntpd.pid"
|
||||
OCF_RESKEY_binpath_default="/usr/sbin/ntpd"
|
||||
OCF_RESKEY_extraconf_default=""
|
||||
|
||||
OCF_RESKEY_host_interface_default="vrouter-host"
|
||||
OCF_RESKEY_namespace_interface_default="vr-ns"
|
||||
OCF_RESKEY_host_ip_default="240.0.0.5"
|
||||
OCF_RESKEY_namespace_ip_default="240.0.0.6"
|
||||
OCF_RESKEY_network_mask_default="30"
|
||||
OCF_RESKEY_route_metric_default="10000"
|
||||
|
||||
: ${OCF_ROOT=${OCF_ROOT_default}}
|
||||
|
||||
: ${OCF_RESKEY_ns=${OCF_RESKEY_ns_default}}
|
||||
: ${OCF_RESKEY_conffile=${OCF_RESKEY_conffile_default}}
|
||||
: ${OCF_RESKEY_pidfile=${OCF_RESKEY_pidfile_default}}
|
||||
: ${OCF_RESKEY_binpath=${OCF_RESKEY_binpath_default}}
|
||||
: ${OCF_RESKEY_extraconf=${OCF_RESKEY_extraconf_default}}
|
||||
|
||||
: ${OCF_RESKEY_host_interface=${OCF_RESKEY_host_interface_default}}
|
||||
: ${OCF_RESKEY_namespace_interface=${OCF_RESKEY_namespace_interface_default}}
|
||||
: ${OCF_RESKEY_host_ip=${OCF_RESKEY_host_ip_default}}
|
||||
: ${OCF_RESKEY_namespace_ip=${OCF_RESKEY_namespace_ip_default}}
|
||||
: ${OCF_RESKEY_network_mask=${OCF_RESKEY_network_mask_default}}
|
||||
: ${OCF_RESKEY_route_metric=${OCF_RESKEY_route_metric_default}}
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs
|
||||
|
||||
USAGE="Usage: $0 {start|stop|restart|status|monitor|validate-all|meta-data}";
|
||||
|
||||
RUN_IN_NS="ip netns exec $OCF_RESKEY_ns "
|
||||
if [[ -z $OCF_RESKEY_ns ]] ; then
|
||||
RUN=''
|
||||
else
|
||||
RUN="$RUN_IN_NS "
|
||||
fi
|
||||
|
||||
##########################################################################
|
||||
|
||||
usage()
|
||||
{
|
||||
echo $USAGE >&2
|
||||
}
|
||||
|
||||
meta_data()
|
||||
{
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="ntp">
|
||||
<version>1.0</version>
|
||||
<longdesc lang="en">
|
||||
This script manages ntp daemon with namespace support
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages an ntp daemon inside a namespace</shortdesc>
|
||||
|
||||
<parameters>
|
||||
|
||||
<parameter name="ns">
|
||||
<longdesc lang="en">
|
||||
Name of network namespace.
|
||||
Should be present.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Name of network namespace.</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_ns_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="conffile">
|
||||
<longdesc lang="en">
|
||||
The ntp daemon configuration file name with full path.
|
||||
For example, "/etc/ntp/ntp.cfg"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Configuration file name with full path</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_conffile_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pidfile">
|
||||
<longdesc lang="en">
|
||||
The ntp pid file path.
|
||||
For example, "/var/run/ntp.pid"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Full path to the ntp pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pidfile_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="binpath">
|
||||
<longdesc lang="en">
|
||||
The ntp binary path.
|
||||
For example, "/usr/sbin/ntp"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Full path to the ntp binary</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binpath_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="extraconf">
|
||||
<longdesc lang="en">
|
||||
Extra command line arguments to pass to ntp.
|
||||
For example, "-f /etc/ntp/shared.cfg"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Extra command line arguments for ntp</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_extraconf_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="host_interface">
|
||||
<longdesc lang="en">
|
||||
The host part of the interface pair used to connect the namespace to the network
|
||||
For example, "vrouter-host"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">The name of the host interface used for namespace</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_host_interface_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="namespace_interface">
|
||||
<longdesc lang="en">
|
||||
The namespace part of the interface pair used to connect the namespace to the network
|
||||
For example, "vrouter-ns"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">The name of the namespace interface used for namespace</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_namespace_interface_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="host_ip">
|
||||
<longdesc lang="en">
|
||||
The IP address used by the host interface. Must be from the same subnet as namesapce IP
|
||||
and uses network_mask to determine subnet.
|
||||
Should not collide with any IP addresses already used in your network.
|
||||
For example, "240.0.0.5"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Host interface IP address</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_host_ip_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="namespace_ip">
|
||||
<longdesc lang="en">
|
||||
The IP address used by the namespace interface. Must be from the same subnet as host IP
|
||||
and uses network_mask to determine subnet.
|
||||
Should not collide with any IP addresses already used in your network.
|
||||
For example, "240.0.0.6"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Namespace interface IP address</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_namespace_ip_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="network_mask">
|
||||
<longdesc lang="en">
|
||||
The network mask length used to determine subnet of the host
|
||||
and the namspace interfaces.
|
||||
For example, "30"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Network mask length</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_network_mask_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="route_metric">
|
||||
<longdesc lang="en">
|
||||
The metric value of the default route set for the pipe
|
||||
link connecting namespace and host. It should be set to
|
||||
a large number to be higher then other default route metrics
|
||||
that could be set to override this default route.
|
||||
If other routes are set eithin the namespace thir metric should
|
||||
be smaller then this number if you want them to be used istead of
|
||||
this route.
|
||||
For example, "1000"
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Namespace default route metric</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_route_metric_default}" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20s"/>
|
||||
<action name="stop" timeout="20s"/>
|
||||
<action name="monitor" depth="0" timeout="20s" interval="60s" />
|
||||
<action name="validate-all" timeout="20s"/>
|
||||
<action name="meta-data" timeout="5s"/>
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
exit $OCF_SUCCESS
|
||||
}
|
||||
|
||||
check_ns() {
|
||||
local ns=`ip netns list | grep "$OCF_RESKEY_ns"`
|
||||
[[ $ns != $OCF_RESKEY_ns ]] && return $OCF_ERR_GENERIC
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
get_ns() {
|
||||
local rc
|
||||
check_ns && return $OCF_SUCCESS
|
||||
|
||||
ocf_run ip netns add $OCF_RESKEY_ns
|
||||
rc=$?
|
||||
ocf_run $RUN_IN_NS ip link set up dev lo
|
||||
|
||||
return $rc
|
||||
}
|
||||
|
||||
get_variables() {
|
||||
get_ns
|
||||
|
||||
CONF_FILE="${OCF_RESKEY_conffile}"
|
||||
COMMAND="$RUN ${OCF_RESKEY_binpath}"
|
||||
PIDFILE="${OCF_RESKEY_pidfile}"
|
||||
}
|
||||
|
||||
set_ns_routing() {
|
||||
nsip() {
|
||||
ip netns exec "${OCF_RESKEY_ns}" ip ${@}
|
||||
}
|
||||
|
||||
# create host-ns veth pair unless it's present
|
||||
ip link | grep -q -w "${OCF_RESKEY_host_interface}:"
|
||||
if [ $? -gt 0 ]; then
|
||||
ocf_log debug "Creating host interface: ${OCF_RESKEY_host_interface} and namespace interface: ${OCF_RESKEY_namespace_interface}"
|
||||
ocf_run ip link add "${OCF_RESKEY_host_interface}" type veth peer name "${OCF_RESKEY_namespace_interface}"
|
||||
fi
|
||||
|
||||
# move the ns part to the namespace
|
||||
ip link | grep -q -w "${OCF_RESKEY_namespace_interface}:"
|
||||
if [ $? -eq 0 ]; then
|
||||
ocf_log debug "Moving interface: ${OCF_RESKEY_namespace_interface} to namespace: ${OCF_RESKEY_ns}"
|
||||
ocf_run ip link set dev "${OCF_RESKEY_namespace_interface}" netns "${OCF_RESKEY_ns}"
|
||||
fi
|
||||
|
||||
# up the host part
|
||||
ocf_log debug "Bringing up host interface: ${OCF_RESKEY_host_interface}"
|
||||
ocf_run ip link set "${OCF_RESKEY_host_interface}" up
|
||||
|
||||
# set host part's ip
|
||||
ip addr show dev "${OCF_RESKEY_host_interface}" | grep -q "inet ${OCF_RESKEY_host_ip}/${OCF_RESKEY_network_mask}"
|
||||
if [ $? -gt 0 ]; then
|
||||
ocf_log debug "Setting host interface: ${OCF_RESKEY_host_interface} IP to: ${OCF_RESKEY_host_ip}/${OCF_RESKEY_network_mask}"
|
||||
ocf_run ip addr add "${OCF_RESKEY_host_ip}/${OCF_RESKEY_network_mask}" dev "${OCF_RESKEY_host_interface}"
|
||||
fi
|
||||
|
||||
# up the ns part
|
||||
ocf_log debug "Bringing up the namespace interface: ${OCF_RESKEY_namespace_interface}"
|
||||
ocf_run nsip link set "${OCF_RESKEY_namespace_interface}" up
|
||||
|
||||
# set ns part's ip
|
||||
nsip addr show dev "${OCF_RESKEY_namespace_interface}" | grep -q "inet ${OCF_RESKEY_namespace_ip}/${OCF_RESKEY_network_mask}"
|
||||
if [ $? -gt 0 ]; then
|
||||
ocf_log debug "Setting namespace interface: ${OCF_RESKEY_namespace_interface} IP to: ${OCF_RESKEY_namespace_ip}/${OCF_RESKEY_network_mask}"
|
||||
ocf_run nsip addr add "${OCF_RESKEY_namespace_ip}/${OCF_RESKEY_network_mask}" dev "${OCF_RESKEY_namespace_interface}"
|
||||
fi
|
||||
|
||||
# set default gateway inside ns
|
||||
nsip route list | grep -q "default via ${OCF_RESKEY_host_ip}"
|
||||
if [ $? -gt 0 ]; then
|
||||
ocf_log debug "Creating default route inside the namespace to ${OCF_RESKEY_host_ip} with metric ${OCF_RESKEY_route_metric}"
|
||||
ocf_run nsip route add default via "${OCF_RESKEY_host_ip}" metric "${OCF_RESKEY_route_metric}"
|
||||
fi
|
||||
|
||||
# set masquerade on host node
|
||||
iptables -t nat -L | grep -q masquerade-for-vrouter-namespace
|
||||
if [ $? -gt 0 ]; then
|
||||
ocf_log debug "Creating NAT rule on the host system for traffic from IP: ${OCF_RESKEY_namespace_ip}"
|
||||
ocf_run iptables -t nat -A POSTROUTING -s "${OCF_RESKEY_namespace_ip}" -j MASQUERADE -m comment --comment "masquerade-for-vrouter-namespace"
|
||||
fi
|
||||
}
|
||||
|
||||
ntp_status() {
|
||||
get_variables
|
||||
if [ -n "${PIDFILE}" -a -f "${PIDFILE}" ]; then
|
||||
# ntp is probably running
|
||||
# get pid from pidfile
|
||||
PID="`cat ${PIDFILE}`"
|
||||
if [ -n "${PID}" ]; then
|
||||
# check if process exists
|
||||
if $RUN ps -p "${PID}" | grep -q ntp; then
|
||||
ocf_log info "ntp daemon running"
|
||||
return $OCF_SUCCESS
|
||||
else
|
||||
ocf_log info "ntp daemon is not running but pid file exists"
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
else
|
||||
ocf_log err "PID file empty!"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
# ntp is not running
|
||||
ocf_log info "ntp daemon is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
}
|
||||
|
||||
ntp_start()
|
||||
{
|
||||
get_variables
|
||||
# if ntp is running return success
|
||||
ntp_status
|
||||
retVal=$?
|
||||
if [ $retVal -eq $OCF_SUCCESS ]; then
|
||||
return $OCF_SUCCESS
|
||||
elif [ $retVal -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "Error. Unknown status."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
if [ "${OCF_RESKEY_ns}" != '' ]; then
|
||||
set_ns_routing
|
||||
fi
|
||||
|
||||
# run the ntp binary
|
||||
ocf_run ${COMMAND} ${OCF_RESKEY_extraconf} -u ntp:ntp -p "${PIDFILE}" -g -c ${CONF_FILE}
|
||||
if [ $? -ne 0 ]; then
|
||||
ocf_log err "Error. ntp daemon returned error $?."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
ocf_log info "Started ntp daemon."
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
ntp_stop()
|
||||
{
|
||||
get_variables
|
||||
if ntp_status ; then
|
||||
PID="`${RUN} cat ${PIDFILE}`"
|
||||
if [ -n "${PID}" ] ; then
|
||||
kill "${PID}"
|
||||
if [ $? -ne 0 ]; then
|
||||
kill -SIGKILL "${PID}"
|
||||
if [ $? -ne 0 ]; then
|
||||
ocf_log err "Error. Could not stop ntp daemon."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
rm -f "${PIDFILE}"
|
||||
fi
|
||||
fi
|
||||
ocf_log info "Stopped ntp daemon."
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
ntp_monitor()
|
||||
{
|
||||
ntp_status
|
||||
}
|
||||
|
||||
ntp_validate_all()
|
||||
{
|
||||
get_variables
|
||||
if [ -n "$OCF_RESKEY_binpath" -a ! -x "$OCF_RESKEY_binpath" ]; then
|
||||
ocf_log err "Binary path $OCF_RESKEY_binpath does not exist."
|
||||
return $OCF_ERR_ARGS
|
||||
fi
|
||||
if [ -n "$OCF_RESKEY_conffile" -a ! -f "$OCF_RESKEY_conffile" ]; then
|
||||
ocf_log err "Config file $OCF_RESKEY_conffile does not exist."
|
||||
return $OCF_ERR_ARGS
|
||||
fi
|
||||
|
||||
if grep -v "^#" "$CONF_FILE" | grep "pidfile" > /dev/null ; then
|
||||
:
|
||||
else
|
||||
ocf_log err "Error. \"pidfile\" entry required in the ntp config file by ntp OCF RA."
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
ntp_restart()
|
||||
{
|
||||
ntp_stop
|
||||
ntp_start
|
||||
}
|
||||
|
||||
#
|
||||
# Main
|
||||
#
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
usage
|
||||
exit $OCF_ERR_ARGS
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
start) ntp_start
|
||||
;;
|
||||
|
||||
stop) ntp_stop
|
||||
;;
|
||||
|
||||
restart) ntp_restart
|
||||
;;
|
||||
|
||||
status) ntp_status
|
||||
;;
|
||||
|
||||
monitor) ntp_monitor
|
||||
;;
|
||||
|
||||
validate-all) ntp_validate_all
|
||||
;;
|
||||
|
||||
meta-data) meta_data
|
||||
;;
|
||||
|
||||
usage) usage; exit $OCF_SUCCESS
|
||||
;;
|
||||
|
||||
*) usage; exit $OCF_ERR_UNIMPLEMENTED
|
||||
;;
|
||||
esac
|
672
files/fuel-ha-utils/ocf/ocf-neutron-dhcp-agent
Normal file
672
files/fuel-ha-utils/ocf/ocf-neutron-dhcp-agent
Normal file
@ -0,0 +1,672 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
#
|
||||
# OpenStack Neutron DHCP Service
|
||||
#
|
||||
# Description: Manages an OpenStack Neutron DHCP Service process as an HA resource
|
||||
#
|
||||
# Authors: Emilien Macchi
|
||||
# Mainly inspired by the Nova Network resource agent written by Emilien Macchi & Sebastien Han
|
||||
#
|
||||
# Support: openstack@lists.launchpad.net
|
||||
# License: Apache Software License (ASL) 2.0
|
||||
#
|
||||
#
|
||||
# See usage() function below for more details ...
|
||||
#
|
||||
# OCF instance parameters:
|
||||
# OCF_RESKEY_binary
|
||||
# OCF_RESKEY_config
|
||||
# OCF_RESKEY_plugin_config
|
||||
# OCF_RESKEY_user
|
||||
# OCF_RESKEY_pid
|
||||
# OCF_RESKEY_amqp_server_port
|
||||
# OCF_RESKEY_additional_parameters
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
#######################################################################
|
||||
|
||||
# Fill in some defaults if no values are specified
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
|
||||
OCF_RESKEY_binary_default="neutron-dhcp-agent"
|
||||
OCF_RESKEY_config_default="/etc/neutron/neutron.conf"
|
||||
OCF_RESKEY_keystone_config_default="/etc/keystone/keystone.conf"
|
||||
OCF_RESKEY_plugin_config_default="/etc/neutron/dhcp_agent.ini"
|
||||
OCF_RESKEY_log_file_default="/var/log/neutron/dhcp-agent.log"
|
||||
OCF_RESKEY_check_state_reports_default=false
|
||||
OCF_RESKEY_state_reports_file_default="/var/lib/neutron/dhcp_agent_report.log"
|
||||
OCF_RESKEY_state_reports_timeout_default=60
|
||||
OCF_RESKEY_user_default="neutron"
|
||||
OCF_RESKEY_pid_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
OCF_RESKEY_amqp_server_port_default="5672" # or "none" for disable checking
|
||||
OCF_RESKEY_os_auth_url_default="http://localhost:5000/v2.0"
|
||||
OCF_RESKEY_username_default="neutron"
|
||||
OCF_RESKEY_password_default="neutron_pass"
|
||||
OCF_RESKEY_tenant_default="services"
|
||||
OCF_RESKEY_multiple_agents_default='true'
|
||||
OCF_RESKEY_rescheduling_tries_default=5
|
||||
OCF_RESKEY_rescheduling_interval_default=33
|
||||
OCF_RESKEY_debug_default='false'
|
||||
|
||||
|
||||
: ${OCF_RESKEY_os_auth_url=${OCF_RESKEY_os_auth_url_default}}
|
||||
: ${OCF_RESKEY_username=${OCF_RESKEY_username_default}}
|
||||
: ${OCF_RESKEY_password=${OCF_RESKEY_password_default}}
|
||||
: ${OCF_RESKEY_tenant=${OCF_RESKEY_tenant_default}}
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_keystone_config=${OCF_RESKEY_keystone_config_default}}
|
||||
: ${OCF_RESKEY_plugin_config=${OCF_RESKEY_plugin_config_default}}
|
||||
: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
: ${OCF_RESKEY_multiple_agents=${OCF_RESKEY_multiple_agents_default}}
|
||||
: ${OCF_RESKEY_amqp_server_port=${OCF_RESKEY_amqp_server_port_default}}
|
||||
: ${OCF_RESKEY_log_file=${OCF_RESKEY_log_file_default}}
|
||||
: ${OCF_RESKEY_check_state_reports=${OCF_RESKEY_check_state_reports_default}}
|
||||
: ${OCF_RESKEY_state_reports_file=${OCF_RESKEY_state_reports_file_default}}
|
||||
: ${OCF_RESKEY_state_reports_timeout=${OCF_RESKEY_state_reports_timeout_default}}
|
||||
: ${OCF_RESKEY_rescheduling_tries=${OCF_RESKEY_rescheduling_tries_default}}
|
||||
: ${OCF_RESKEY_rescheduling_interval=${OCF_RESKEY_rescheduling_interval_default}}
|
||||
: ${OCF_RESKEY_debug=${OCF_RESKEY_debug_default}}
|
||||
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<UEND
|
||||
usage: $0 (start|stop|validate-all|meta-data|status|monitor)
|
||||
|
||||
$0 manages an OpenStack DHCP Service (${OCF_RESKEY_binary}) process as an HA resource
|
||||
|
||||
The 'start' operation starts the networking service.
|
||||
The 'stop' operation stops the networking service.
|
||||
The 'validate-all' operation reports whether the parameters are valid
|
||||
The 'meta-data' operation reports this RA's meta-data information
|
||||
The 'status' operation reports whether the networking service is running
|
||||
The 'monitor' operation reports whether the networking service seems to be working
|
||||
|
||||
UEND
|
||||
}
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="neutron-dhcp-agent">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
Resource agent for the OpenStack Neutron DHCP Service (${OCF_RESKEY_binary})
|
||||
May manage a neutron-dhcp-agent instance or a clone set that
|
||||
creates a distributed neutron-dhcp-agent cluster.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages the OpenStack DHCP Service (${OCF_RESKEY_binary})</shortdesc>
|
||||
<parameters>
|
||||
|
||||
<parameter name="binary" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack DHCP Agent server binary (${OCF_RESKEY_binary})
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack DHCP Agent server binary (${OCF_RESKEY_binary})</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binary_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack Neutron Service (neutron-server) configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack DHCP Agent (neutron-server) config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="keystone_config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the Keystone configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Keystone config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_keystone_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="plugin_config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack DHCP Service (${OCF_RESKEY_binary}) configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack DHCP Agent (${OCF_RESKEY_binary}) config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_plugin_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="user" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
User running OpenStack DHCP Service (${OCF_RESKEY_binary})
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack DHCP Service (${OCF_RESKEY_binary}) user</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_user_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="multiple_agents" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Flag, that switch RCS-agent behavior for multiple or single DHCP-agent.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Switsh between multiple or single DHCP-agent behavior</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_multiple_agents_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pid" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The pid file to use for this OpenStack DHCP Service (${OCF_RESKEY_binary}) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack DHCP Service (${OCF_RESKEY_binary}) pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pid_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="amqp_server_port" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The listening port number of the AMQP server.
|
||||
Mandatory to perform a monitor check.
|
||||
Set to 'none' for disable this kind of checking.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">AMQP listening port</shortdesc>
|
||||
<content type="integer" default="${OCF_RESKEY_amqp_server_port_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="log_file" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The log file to use for this OpenStack DHCP Service (${OCF_RESKEY_binary}) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack DHCP Service (${OCF_RESKEY_binary}) log file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_log_file_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="check_state_reports" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The flag, which enables or disables additional monitoring
|
||||
based on agent's local state reports
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Enable or disable local state reports based monitoring</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_check_state_reports_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="state_reports_file" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
This file contains DHCP agent local state report information.
|
||||
There're three section in it: STARTUP, RPC_STATE_REPORT and SYNC_STATE.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">DHCP agent local state report file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_state_reports_file_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="state_reports_timeout" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The timeout value for DHCP agent to update its local state report.
|
||||
If it takes more time than the specified value agent is considered to be dead.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">DHCP agent local state reports timeout</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_state_reports_timeout_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="username" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Neutron username for port list fetching
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Neutron username</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_username_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="password" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Neutron password for port list fetching
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Neutron password</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_password_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="os_auth_url" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
URL of keystone
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Keystone URL</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_os_auth_url_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="tenant" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Admin tenant name
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Admin tenant</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_tenant_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="rescheduling_tries" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Tries to start rescheduling script after start of agent.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Tries to start rescheduling script after start of agent.</shortdesc>
|
||||
<content type="boolean" default="${OCF_RESKEY_rescheduling_tries_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="rescheduling_interval" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Interval between starts of rescheduling script.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Interval between starts of rescheduling script.</shortdesc>
|
||||
<content type="boolean" default="${OCF_RESKEY_rescheduling_interval_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="additional_parameters" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Additional parameters to pass on to the OpenStack DHCP Service (${OCF_RESKEY_binary})
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Additional parameters for neutron-dhcp-agent</shortdesc>
|
||||
<content type="string" />
|
||||
</parameter>
|
||||
|
||||
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20" />
|
||||
<action name="stop" timeout="20" />
|
||||
<action name="status" timeout="20" />
|
||||
<action name="monitor" timeout="30" interval="20" />
|
||||
<action name="validate-all" timeout="5" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
get_worker_pid() {
|
||||
local options
|
||||
local pid
|
||||
# FIXME: Remove if condition and set 'falo' statically once Fuel
|
||||
# discontinue support of Ubuntu 12.04 and CentOs 6.x where -a was not defined.
|
||||
if pgrep -V | awk 'match($0, /[0-9]\.[0-9].*/) {if (substr($0, RSTART, RLENGTH) < 3.3) {exit 1}}'; then
|
||||
options='falo'
|
||||
else
|
||||
options='flo'
|
||||
fi
|
||||
pid=`pgrep -u ${OCF_RESKEY_user} -${options} ${OCF_RESKEY_binary} | awk '/python \/usr\/bin/ {print $1}'`
|
||||
echo $pid
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Functions invoked by resource manager actions
|
||||
|
||||
neutron_dhcp_agent_validate() {
|
||||
local rc
|
||||
|
||||
check_binary $OCF_RESKEY_binary
|
||||
check_binary netstat
|
||||
|
||||
# A config file on shared storage that is not available
|
||||
# during probes is OK.
|
||||
if [ ! -f $OCF_RESKEY_config ]; then
|
||||
if ! ocf_is_probe; then
|
||||
ocf_log err "Config $OCF_RESKEY_config doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
ocf_log_warn "Config $OCF_RESKEY_config not available during a probe"
|
||||
fi
|
||||
|
||||
getent passwd $OCF_RESKEY_user >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "User $OCF_RESKEY_user doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
setup_auth() {
|
||||
# setup token-based authentication if it possible
|
||||
AUTH_TOKEN=""
|
||||
|
||||
if [[ -f $OCF_RESKEY_keystone_config ]] ; then
|
||||
AUTH_TOKEN=$(grep -v '#' $OCF_RESKEY_keystone_config | grep -i 'admin_token\s*=\s*' | awk -F'=' '{print $2}')
|
||||
fi
|
||||
|
||||
AUTH_TAIL=""
|
||||
if [[ -n "$AUTH_TOKEN" ]] ; then
|
||||
AUTH_TAIL="--admin-auth-url=${OCF_RESKEY_os_auth_url} --auth-token=${AUTH_TOKEN}"
|
||||
fi
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
neutron_dhcp_agent_status() {
|
||||
local pid
|
||||
local f_pid
|
||||
local rc
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${OCF_RESKEY_pid} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
ocf_log debug "Create pid file dir: ${PID_DIR} and chown to ${OCF_RESKEY_user}"
|
||||
mkdir -p "${PID_DIR}"
|
||||
chown -R ${OCF_RESKEY_user} "${PID_DIR}"
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
pid=`get_worker_pid`
|
||||
if [ "xxx$pid" == "xxx" ] ; then
|
||||
ocf_log warn "OpenStack Neutron agent '$OCF_RESKEY_binary' not running."
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
#ocf_log debug "PID='$pid'"
|
||||
|
||||
# Check PID file and create if need
|
||||
if [ ! -f $OCF_RESKEY_pid ] ; then
|
||||
ocf_log warn "OpenStack Neutron agent (${OCF_RESKEY_binary}) was run, but no PID file found."
|
||||
ocf_log warn "Writing PID='$pid' to '$OCF_RESKEY_pid' for '${OCF_RESKEY_binary}' worker..."
|
||||
echo $pid > $OCF_RESKEY_pid
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# compare PID from file with PID from `pgrep...`
|
||||
f_pid=`cat $OCF_RESKEY_pid | tr '\n' ' ' | awk '{print $1}'`
|
||||
if [ "xxx$pid" == "xxx$f_pid" ]; then
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# at this point we have PID file and PID from it
|
||||
# defferents with PID from `pgrep...`
|
||||
if [ ! -d "/proc/$f_pid" ] || [ "xxx$f_pid" == "xxx" ] ; then
|
||||
# process with PID from PID-file not found
|
||||
ocf_log warn "Old PID file $OCF_RESKEY_pid found, but no running processes with PID=$f_pid found."
|
||||
ocf_log warn "PID-file will be re-created (with PID=$pid)."
|
||||
echo $pid > $OCF_RESKEY_pid
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# at this point we have alien PID-file and running prosess with this PID.
|
||||
ocf_log warn "Another daemon (with PID=$f_pid) running with PID file '$OCF_RESKEY_pid'. My PID=$pid"
|
||||
return $OCF_ERR_GENERIC
|
||||
}
|
||||
|
||||
get_local_reports_value() {
|
||||
|
||||
local SECTION
|
||||
local KEY
|
||||
local VALUE
|
||||
|
||||
SECTION=$1
|
||||
KEY=$2
|
||||
VALUE=$(awk "/$SECTION/,/}/" $OCF_RESKEY_state_reports_file | grep $KEY | awk '{$1=""; print $0}' | tr -d "\",")
|
||||
echo $VALUE
|
||||
}
|
||||
|
||||
check_local_reports() {
|
||||
|
||||
local SECTIONS
|
||||
local SYSTIME
|
||||
local RPC_STATE_TIMESTAMP
|
||||
|
||||
if [ ! -f $OCF_RESKEY_state_reports_file ] ; then
|
||||
ocf_log warn "State reports file wasn't found"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
SECTIONS="STARTUP RPC_STATE_REPORT SYNC_STATE"
|
||||
SYSTIME=$(date +%s)
|
||||
RPC_STATE_TIMESTAMP=$(get_local_reports_value RPC_STATE_REPORT Timestamp)
|
||||
RPC_STATE_TIMESTAMP=${RPC_STATE_TIMESTAMP%.*}
|
||||
|
||||
if [[ $(($SYSTIME-$RPC_STATE_TIMESTAMP)) -gt $OCF_RESKEY_state_reports_timeout ]] ; then
|
||||
ocf_log err "Agent is not reporting for too long"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
for SECTION in $SECTIONS ; do
|
||||
STATUS=$(get_local_reports_value $SECTION Status)
|
||||
if [[ "$STATUS" =~ "failure" ]] ; then
|
||||
SINCE=$(date --date="$(get_local_reports_value SYNC_STATE Since)" +%s)
|
||||
if [[ $(($SYSTIME-$SINCE)) -gt $OCF_RESKEY_state_reports_timeout ]] ; then
|
||||
ocf_log err "$SECTION report is in failure status for too long"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
get_ns_list() {
|
||||
local rv=`ip netns list | grep -Ee "^qdhcp-.*"`
|
||||
echo $rv
|
||||
}
|
||||
|
||||
get_pid_list_for_ns_list() {
|
||||
# Parameters contain namespace names for searching pids
|
||||
local ns_list="$@"
|
||||
local pids=`for netns in $ns_list ; do ip netns pids $netns ; done`
|
||||
echo $pids
|
||||
}
|
||||
|
||||
clean_up() {
|
||||
# kill processes inside network namespaces
|
||||
ns_list=`get_ns_list`
|
||||
|
||||
# kill all proceses from all dhcp-agent's net.namespaces, that using ip
|
||||
count=3 # we will try kill process 3 times
|
||||
while [ $count -gt 0 ]; do
|
||||
# we can't use ps, because ps can't select processes for given network namespace
|
||||
inside_ns_pids=`get_pid_list_for_ns_list "$ns_list"`
|
||||
if [ -z "$inside_ns_pids" ] ; then
|
||||
break
|
||||
fi
|
||||
ocf_run kill $inside_ns_pids
|
||||
sleep 1
|
||||
((count--))
|
||||
done
|
||||
|
||||
# kill all remaining proceses, that not died by simple kill
|
||||
inside_ns_pids=`get_pid_list_for_ns_list "$ns_list"`
|
||||
if [ ! -z "$inside_ns_pids" ] ; then
|
||||
for ns_pid in $inside_ns_pids ; do
|
||||
ocf_run kill -9 $ns_pid
|
||||
done
|
||||
fi
|
||||
|
||||
# cleanup network interfaces
|
||||
q-agent-cleanup.py --agent=dhcp --cleanup-ports
|
||||
}
|
||||
|
||||
clean_up_namespaces() {
|
||||
# kill unnided network namespaces.
|
||||
#
|
||||
# Be carefully. In each network namespace shouldn't be any processes
|
||||
# using network!!! use clean_up before it
|
||||
ns_list=`get_ns_list`
|
||||
if [ ! -z "$ns_list" ] ; then
|
||||
for ns_name in $ns_list ; do
|
||||
ocf_run ip --force netns del $ns_name
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
neutron_dhcp_agent_monitor() {
|
||||
local rc
|
||||
local pid
|
||||
local network_amqp_check
|
||||
|
||||
neutron_dhcp_agent_status
|
||||
rc=$?
|
||||
|
||||
# If status returned anything but success, return that immediately
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
return $rc
|
||||
fi
|
||||
|
||||
|
||||
if ocf_is_true "$OCF_RESKEY_check_state_reports" ; then
|
||||
check_local_reports
|
||||
rc=$?
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
return $rc
|
||||
fi
|
||||
fi
|
||||
|
||||
ocf_log debug "OpenStack DHCP Agent (neutron-dhcp-agent) monitor succeeded"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
|
||||
neutron_dhcp_agent_start() {
|
||||
local rc
|
||||
neutron_dhcp_agent_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_SUCCESS ]; then
|
||||
ocf_log info "OpenStack DHCP Agent (${OCF_RESKEY_binary}) already running"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
clean_up
|
||||
sleep 1
|
||||
clean_up_namespaces
|
||||
rm -f $OCF_RESKEY_state_reports_file
|
||||
|
||||
# run and detach to background agent as daemon.
|
||||
# Don't use ocf_run as we're sending the tool's output to /dev/null
|
||||
su ${OCF_RESKEY_user} -s /bin/sh -c "${OCF_RESKEY_binary} --config-file=$OCF_RESKEY_config \
|
||||
--config-file=$OCF_RESKEY_plugin_config --log-file=$OCF_RESKEY_log_file $OCF_RESKEY_additional_parameters \
|
||||
>> /dev/null"' 2>&1 & echo \$! > $OCF_RESKEY_pid'
|
||||
ocf_log debug "Create pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
|
||||
# Spin waiting for the server to come up.
|
||||
# Let the CRM/LRM time us out if required
|
||||
while true; do
|
||||
neutron_dhcp_agent_monitor
|
||||
rc=$?
|
||||
[ $rc -eq $OCF_SUCCESS ] && break
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "OpenStack DHCP Agent (${OCF_RESKEY_binary}) start failed"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
if ! ocf_is_true "$OCF_RESKEY_multiple_agents" ; then
|
||||
# detach deffered rescheduling procedure
|
||||
RESCHEDULING_CMD="q-agent-cleanup.py --agent=dhcp --reschedule --remove-dead ${AUTH_TAIL} 2>&1 >> /var/log/neutron/rescheduling.log"
|
||||
RESCH_CMD=''
|
||||
for ((i=0; i<$OCF_RESKEY_rescheduling_tries; i++)) ; do
|
||||
RESCH_CMD="$RESCH_CMD sleep $OCF_RESKEY_rescheduling_interval ; $RESCHEDULING_CMD ;"
|
||||
done
|
||||
bash -c "$RESCH_CMD" &
|
||||
fi
|
||||
|
||||
ocf_log info "OpenStack DHCP Agent (${OCF_RESKEY_binary}) started"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
|
||||
neutron_dhcp_agent_stop() {
|
||||
local rc
|
||||
local pid
|
||||
|
||||
neutron_dhcp_agent_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
clean_up
|
||||
ocf_log info "OpenStack DHCP Agent (${OCF_RESKEY_binary}) already stopped"
|
||||
sleep 1
|
||||
clean_up_namespaces
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
#Try SIGTERM
|
||||
pid=`get_worker_pid`
|
||||
# stop waiting
|
||||
shutdown_timeout=15
|
||||
iteration_time=3
|
||||
if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
|
||||
shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-6))
|
||||
fi
|
||||
all_inside_ns_pids=`get_pid_list_for_ns_list $(get_ns_list)`
|
||||
all_pids="$pid $all_inside_ns_pids"
|
||||
count=0
|
||||
alive=1
|
||||
while [ $alive -gt 0 ] && [ $count -lt $shutdown_timeout ]; do
|
||||
alive=0
|
||||
ocf_run kill -s TERM $all_pids
|
||||
sleep $iteration_time
|
||||
#Check if processes are alive after command kill
|
||||
#if yes, send to them the term signal again
|
||||
np=""
|
||||
for pid in $all_pids ; do
|
||||
ocf_run kill -s 0 $pid
|
||||
if [ $? -eq 0 ]; then
|
||||
np="$np $pid"
|
||||
((alive++))
|
||||
fi
|
||||
done
|
||||
if [ $alive -gt 0 ] ; then
|
||||
all_pids=$np
|
||||
fi
|
||||
((count+=$iteration_time))
|
||||
ocf_log debug "OpenStack DHCP Agent (${OCF_RESKEY_binary}) still hasn't stopped yet. Waiting ..."
|
||||
done
|
||||
#Send the kill signal to processes which are still alive
|
||||
if [ $alive -gt 0 ] ; then
|
||||
alive=0
|
||||
ocf_run kill -s KILL $all_pids
|
||||
sleep 1
|
||||
for pid in $all_pids ; do
|
||||
ocf_run kill -s 0 $pid
|
||||
if [ $? -eq 0 ]; then
|
||||
((alive++))
|
||||
fi
|
||||
done
|
||||
if [ $alive -gt 0 ] ; then
|
||||
ocf_log err "OpenStack DHCP Agent (${OCF_RESKEY_binary}) stop failed"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
ocf_log info "OpenStack DHCP Agent (${OCF_RESKEY_binary}) stopped"
|
||||
|
||||
ocf_log debug "Delete pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
rm -f $OCF_RESKEY_pid
|
||||
|
||||
# cleanup network interfaces
|
||||
q-agent-cleanup.py --agent=dhcp --cleanup-ports
|
||||
clean_up_namespaces
|
||||
if ! ocf_is_true "$OCF_RESKEY_multiple_agents" ; then
|
||||
q-agent-cleanup.py --agent=dhcp --remove-self ${AUTH_TAIL} 2>&1 >> /var/log/neutron/rescheduling.log &
|
||||
fi
|
||||
sleep 3
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
case "$1" in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS;;
|
||||
usage|help) usage
|
||||
exit $OCF_SUCCESS;;
|
||||
esac
|
||||
|
||||
# Anything except meta-data and help must pass validation
|
||||
neutron_dhcp_agent_validate || exit $?
|
||||
setup_auth || exit $?
|
||||
umask 0022
|
||||
|
||||
# What kind of method was invoked?
|
||||
case "$1" in
|
||||
start) neutron_dhcp_agent_start;;
|
||||
stop) neutron_dhcp_agent_stop;;
|
||||
status) neutron_dhcp_agent_status;;
|
||||
monitor) neutron_dhcp_agent_monitor;;
|
||||
validate-all) ;;
|
||||
*) usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED;;
|
||||
esac
|
684
files/fuel-ha-utils/ocf/ocf-neutron-l3-agent
Normal file
684
files/fuel-ha-utils/ocf/ocf-neutron-l3-agent
Normal file
@ -0,0 +1,684 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
#
|
||||
# OpenStack L3 Service (neutron-l3-agent)
|
||||
#
|
||||
# Description: Manages an OpenStack L3 Service (neutron-l3-agent) process as an HA resource
|
||||
#
|
||||
# Authors: Emilien Macchi
|
||||
# Mainly inspired by the Nova Network resource agent written by Emilien Macchi & Sebastien Han
|
||||
#
|
||||
# Support: openstack@lists.launchpad.net
|
||||
# License: Apache Software License (ASL) 2.0
|
||||
#
|
||||
#
|
||||
# See usage() function below for more details ...
|
||||
#
|
||||
# OCF instance parameters:
|
||||
# OCF_RESKEY_binary
|
||||
# OCF_RESKEY_config
|
||||
# OCF_RESKEY_plugin_config
|
||||
# OCF_RESKEY_user
|
||||
# OCF_RESKEY_pid
|
||||
# OCF_RESKEY_neutron_server_port
|
||||
# OCF_RESKEY_additional_parameters
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
#######################################################################
|
||||
|
||||
# Fill in some defaults if no values are specified
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
|
||||
OCF_RESKEY_binary_default="neutron-l3-agent"
|
||||
OCF_RESKEY_config_default="/etc/neutron/neutron.conf"
|
||||
OCF_RESKEY_keystone_config_default="/etc/keystone/keystone.conf"
|
||||
OCF_RESKEY_plugin_config_default="/etc/neutron/l3_agent.ini"
|
||||
OCF_RESKEY_log_file_default="/var/log/neutron/l3-agent.log"
|
||||
OCF_RESKEY_check_state_reports_default=false
|
||||
OCF_RESKEY_state_reports_file_default="/var/lib/neutron/l3_agent_report.log"
|
||||
OCF_RESKEY_state_reports_timeout_default=60
|
||||
OCF_RESKEY_user_default="neutron"
|
||||
OCF_RESKEY_pid_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
OCF_RESKEY_os_auth_url_default="http://localhost:5000/v2.0"
|
||||
OCF_RESKEY_username_default="neutron"
|
||||
OCF_RESKEY_password_default="neutron_pass"
|
||||
OCF_RESKEY_tenant_default="services"
|
||||
OCF_RESKEY_external_bridge_default="br-ex"
|
||||
OCF_RESKEY_multiple_agents_default=true
|
||||
OCF_RESKEY_rescheduling_tries_default=5
|
||||
OCF_RESKEY_rescheduling_interval_default=33
|
||||
OCF_RESKEY_debug_default=false
|
||||
|
||||
: ${OCF_RESKEY_os_auth_url=${OCF_RESKEY_os_auth_url_default}}
|
||||
: ${OCF_RESKEY_username=${OCF_RESKEY_username_default}}
|
||||
: ${OCF_RESKEY_password=${OCF_RESKEY_password_default}}
|
||||
: ${OCF_RESKEY_tenant=${OCF_RESKEY_tenant_default}}
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_keystone_config=${OCF_RESKEY_keystone_config_default}}
|
||||
: ${OCF_RESKEY_plugin_config=${OCF_RESKEY_plugin_config_default}}
|
||||
: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
: ${OCF_RESKEY_multiple_agents=${OCF_RESKEY_multiple_agents_default}}
|
||||
: ${OCF_RESKEY_external_bridge=${OCF_RESKEY_external_bridge_default}}
|
||||
: ${OCF_RESKEY_debug=${OCF_RESKEY_debug_default}}
|
||||
: ${OCF_RESKEY_rescheduling_tries=${OCF_RESKEY_rescheduling_tries_default}}
|
||||
: ${OCF_RESKEY_rescheduling_interval=${OCF_RESKEY_rescheduling_interval_default}}
|
||||
: ${OCF_RESKEY_log_file=${OCF_RESKEY_log_file_default}}
|
||||
: ${OCF_RESKEY_check_state_reports=${OCF_RESKEY_check_state_reports_default}}
|
||||
: ${OCF_RESKEY_state_reports_file=${OCF_RESKEY_state_reports_file_default}}
|
||||
: ${OCF_RESKEY_state_reports_timeout=${OCF_RESKEY_state_reports_timeout_default}}
|
||||
|
||||
#######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<UEND
|
||||
usage: $0 (start|stop|validate-all|meta-data|status|monitor)
|
||||
|
||||
$0 manages an OpenStack L3 Service (neutron-l3-agent) process as an HA resource
|
||||
|
||||
The 'start' operation starts the networking service.
|
||||
The 'stop' operation stops the networking service.
|
||||
The 'validate-all' operation reports whether the parameters are valid
|
||||
The 'meta-data' operation reports this RA's meta-data information
|
||||
The 'status' operation reports whether the networking service is running
|
||||
The 'monitor' operation reports whether the networking service seems to be working
|
||||
|
||||
UEND
|
||||
}
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="neutron-l3-agent">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
Resource agent for the OpenStack L3 agent (neutron-l3-agent)
|
||||
May manage a neutron-l3-agent instance or a clone set that
|
||||
creates a distributed neutron-l3-agent cluster.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages the OpenStack L3 Service (neutron-l3-agent)</shortdesc>
|
||||
<parameters>
|
||||
|
||||
<parameter name="binary" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack L3 agent server binary (neutron-l3-agent)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack L3 agent server binary (neutron-l3-agent)</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binary_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack L3 agent (neutron-server) configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack L3 agent (neutron-server) config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="keystone_config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the Keystone configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Keystone config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_keystone_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="plugin_config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack L3 Service (neutron-l3-agent) configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack L3 agent (neutron-l3-agent) config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_plugin_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="user" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
User running OpenStack L3 Service (neutron-l3-agent)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack L3 Service (neutron-l3-agent) user</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_user_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pid" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The pid file to use for this OpenStack L3 Service (neutron-l3-agent) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack L3 Service (neutron-l3-agent) pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pid_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="multiple_agents" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Flag, that switch RCS-agent behavior for multiple or single L3-agent.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Switsh between multiple or single L3-agent behavior</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_multiple_agents_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="log_file" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The log file to use for this OpenStack L3 Service (neutron-l3-agent) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack L3 Service (neutron-l3-agent) log file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_log_file_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="check_state_reports" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The flag, which enables or disables additional monitoring
|
||||
based on agent's local state reports
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Enable or disable local state reports based monitoring</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_check_state_reports_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="state_reports_file" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
This file contains L3 agent local state report information.
|
||||
There're three section in it: STARTUP, RPC_STATE_REPORT and SYNC_STATE.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">L3 agent local state report file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_state_reports_file_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="state_reports_timeout" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The timeout value for L3 agent to update its local state report.
|
||||
If it takes more time than the specified value agent is considered to be dead.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">L3 agent local state reports timeout</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_state_reports_timeout_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="neutron_server_port" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The listening port number of the AMQP server. Mandatory to perform a monitor check
|
||||
</longdesc>
|
||||
<shortdesc lang="en">AMQP listening port</shortdesc>
|
||||
<content type="integer" default="${OCF_RESKEY_neutron_server_port_default}" />
|
||||
</parameter>
|
||||
|
||||
|
||||
<parameter name="username" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Neutron username for port list fetching
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Neutron username</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_username_default}" />
|
||||
</parameter>
|
||||
|
||||
|
||||
<parameter name="password" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Neutron password for port list fetching
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Neutron password</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_password_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="os_auth_url" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
URL of keystone
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Keystone URL</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_os_auth_url_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="tenant" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Admin tenant name
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Admin tenant</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_tenant_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="external_bridge" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
External bridge for l3-agent
|
||||
</longdesc>
|
||||
<shortdesc lang="en">External bridge</shortdesc>
|
||||
<content type="string" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="debug" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Enable debug logging
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Enable debug logging</shortdesc>
|
||||
<content type="boolean" default="false"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="rescheduling_tries" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Tries to start rescheduling script after start of agent.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Tries to start rescheduling script after start of agent.</shortdesc>
|
||||
<content type="boolean" default="${OCF_RESKEY_rescheduling_tries_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="rescheduling_interval" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Interval between starts of rescheduling script.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Interval between starts of rescheduling script.</shortdesc>
|
||||
<content type="boolean" default="${OCF_RESKEY_rescheduling_interval_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="syslog" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Enable logging to syslog
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Enable logging to syslog</shortdesc>
|
||||
<content type="boolean" default="false"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="additional_parameters" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Additional parameters to pass on to the OpenStack L3 Service (neutron-l3-agent)
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Additional parameters for neutron-l3-agent</shortdesc>
|
||||
<content type="string" />
|
||||
</parameter>
|
||||
|
||||
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20" />
|
||||
<action name="stop" timeout="20" />
|
||||
<action name="status" timeout="20" />
|
||||
<action name="monitor" timeout="30" interval="20" />
|
||||
<action name="validate-all" timeout="5" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
get_worker_pid() {
|
||||
local options
|
||||
local pid
|
||||
# FIXME: Remove if condition and set 'falo' statically once Fuel
|
||||
# discontinue support of Ubuntu 12.04 and CentOs 6.x where -a was not defined.
|
||||
if pgrep -V | awk 'match($0, /[0-9]\.[0-9].*/) {if (substr($0, RSTART, RLENGTH) < 3.3) {exit 1}}'; then
|
||||
options='falo'
|
||||
else
|
||||
options='flo'
|
||||
fi
|
||||
pid=`pgrep -u ${OCF_RESKEY_user} -${options} ${OCF_RESKEY_binary} | awk '/python \/usr\/bin/ {print $1}'`
|
||||
echo $pid
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Functions invoked by resource manager actions
|
||||
|
||||
neutron_l3_agent_validate() {
|
||||
local rc
|
||||
|
||||
check_binary $OCF_RESKEY_binary
|
||||
check_binary netstat
|
||||
|
||||
# A config file on shared storage that is not available
|
||||
# during probes is OK.
|
||||
if [ ! -f $OCF_RESKEY_config ]; then
|
||||
if ! ocf_is_probe; then
|
||||
ocf_log err "Config $OCF_RESKEY_config doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
ocf_log_warn "Config $OCF_RESKEY_config not available during a probe"
|
||||
fi
|
||||
|
||||
getent passwd $OCF_RESKEY_user >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "User $OCF_RESKEY_user doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
setup_auth() {
|
||||
# setup token-based authentication if it possible
|
||||
AUTH_TOKEN=""
|
||||
|
||||
if [[ -f $OCF_RESKEY_keystone_config ]] ; then
|
||||
AUTH_TOKEN=$(grep -v '#' $OCF_RESKEY_keystone_config | grep -i 'admin_token\s*=\s*' | awk -F'=' '{print $2}')
|
||||
fi
|
||||
|
||||
AUTH_TAIL=""
|
||||
if [[ -n "$AUTH_TOKEN" ]] ; then
|
||||
AUTH_TAIL="--admin-auth-url=${OCF_RESKEY_os_auth_url} --auth-token=${AUTH_TOKEN}"
|
||||
fi
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
neutron_l3_agent_status() {
|
||||
local pid
|
||||
local f_pid
|
||||
local rc
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${OCF_RESKEY_pid} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
ocf_log debug "Create pid file dir: ${PID_DIR} and chown to ${OCF_RESKEY_user}"
|
||||
mkdir -p "${PID_DIR}"
|
||||
chown -R ${OCF_RESKEY_user} "${PID_DIR}"
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
pid=`get_worker_pid`
|
||||
if [ "xxx$pid" == "xxx" ] ; then
|
||||
ocf_log warn "OpenStack Neutron agent '$OCF_RESKEY_binary' not running."
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
#ocf_log debug "PID='$pid'"
|
||||
|
||||
# Check PID file and create if need
|
||||
if [ ! -f $OCF_RESKEY_pid ] ; then
|
||||
ocf_log warn "OpenStack Neutron agent (${OCF_RESKEY_binary}) was run, but no PID file found."
|
||||
ocf_log warn "Writing PID='$pid' to '$OCF_RESKEY_pid' for '${OCF_RESKEY_binary}' worker..."
|
||||
echo $pid > $OCF_RESKEY_pid
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# compare PID from file with PID from `pgrep...`
|
||||
f_pid=`cat $OCF_RESKEY_pid | tr '\n' ' ' | awk '{print $1}'`
|
||||
if [ "xxx$pid" == "xxx$f_pid" ]; then
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# at this point we have PID file and PID from it
|
||||
# differents with PID from `pgrep...`
|
||||
if [ ! -d "/proc/$f_pid" ] || [ "xxx$f_pid" == "xxx" ] ; then
|
||||
# process with PID from PID-file not found
|
||||
ocf_log warn "Old PID file $OCF_RESKEY_pid found, but no running processes with PID=$f_pid found."
|
||||
ocf_log warn "PID-file will be re-created (with PID=$pid)."
|
||||
echo $pid > $OCF_RESKEY_pid
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# at this point we have alien PID-file and running prosess with this PID.
|
||||
ocf_log warn "Another daemon (with PID=$f_pid) running with PID file '$OCF_RESKEY_pid'. My PID=$pid"
|
||||
return $OCF_ERR_GENERIC
|
||||
}
|
||||
|
||||
get_local_reports_value() {
|
||||
|
||||
local SECTION
|
||||
local KEY
|
||||
local VALUE
|
||||
|
||||
SECTION=$1
|
||||
KEY=$2
|
||||
# 'cat' is done here to avoid problems with file opening by awk due to permanent rewrites by the agent
|
||||
VALUE=$(awk "/$SECTION/,/}/" $OCF_RESKEY_state_reports_file | grep $KEY | awk '{$1=""; print $0}' | tr -d "\",")
|
||||
echo $VALUE
|
||||
}
|
||||
|
||||
check_local_reports() {
|
||||
|
||||
local SECTIONS
|
||||
local SYSTIME
|
||||
local RPC_STATE_TIMESTAMP
|
||||
|
||||
if [ ! -f $OCF_RESKEY_state_reports_file ] ; then
|
||||
ocf_log warn "State reports file wasn't found"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
SECTIONS="STARTUP RPC_STATE_REPORT SYNC_STATE"
|
||||
SYSTIME=$(date +%s)
|
||||
RPC_STATE_TIMESTAMP=$(get_local_reports_value RPC_STATE_REPORT Timestamp)
|
||||
RPC_STATE_TIMESTAMP=${RPC_STATE_TIMESTAMP%.*}
|
||||
|
||||
if [[ $(($SYSTIME-$RPC_STATE_TIMESTAMP)) -gt $OCF_RESKEY_state_reports_timeout ]] ; then
|
||||
ocf_log err "Agent is not reporting for too long"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
for SECTION in $SECTIONS ; do
|
||||
STATUS=$(get_local_reports_value $SECTION Status)
|
||||
if [[ "$STATUS" =~ "failure" ]] ; then
|
||||
SINCE=$(date --date="$(get_local_reports_value SYNC_STATE Since)" +%s)
|
||||
if [[ $(($SYSTIME-$SINCE)) -gt $OCF_RESKEY_state_reports_timeout ]] ; then
|
||||
ocf_log err "$SECTION report is in failure status for too long"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
get_ns_list() {
|
||||
local rv=`ip netns list | grep -Ee "^qrouter-.*"`
|
||||
echo $rv
|
||||
}
|
||||
|
||||
get_pid_list_for_ns_list() {
|
||||
# Parameters contain namespace names for searching pids
|
||||
local ns_list="$@"
|
||||
local pids=`for netns in $ns_list ; do ip netns pids $netns ; done`
|
||||
echo $pids
|
||||
}
|
||||
|
||||
clean_up() {
|
||||
# kill processes inside network namespaces
|
||||
ns_list=`get_ns_list`
|
||||
|
||||
# kill all proceses from all dhcp-agent's net.namespaces, that using ip
|
||||
count=3 # we will try kill process 3 times
|
||||
while [ $count -gt 0 ]; do
|
||||
# we can't use ps, because ps can't select processes for given network namespace
|
||||
inside_ns_pids=`get_pid_list_for_ns_list "$ns_list"`
|
||||
if [ -z "$inside_ns_pids" ] ; then
|
||||
break
|
||||
fi
|
||||
for ns_pid in $inside_ns_pids ; do
|
||||
ocf_run kill $ns_pid
|
||||
done
|
||||
sleep 1
|
||||
count=$(($count - 1))
|
||||
done
|
||||
|
||||
# kill all remaining proceses, that not died by simple kill
|
||||
inside_ns_pids=`get_pid_list_for_ns_list "$ns_list"`
|
||||
if [ ! -z "$inside_ns_pids" ] ; then
|
||||
for ns_pid in $inside_ns_pids ; do
|
||||
ocf_run kill -9 $ns_pid
|
||||
done
|
||||
fi
|
||||
|
||||
# cleanup network interfaces
|
||||
q-agent-cleanup.py --agent=l3 --cleanup-ports
|
||||
}
|
||||
|
||||
clean_up_namespaces() {
|
||||
# kill unnided network namespaces.
|
||||
#
|
||||
# Be carefully. In each network namespace shouldn't be any processes
|
||||
# using network!!! use clean_up before it
|
||||
ns_list=`get_ns_list`
|
||||
if [ ! -z "$ns_list" ] ; then
|
||||
for ns_name in $ns_list ; do
|
||||
ocf_run ip --force netns del $ns_name
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
neutron_l3_agent_monitor() {
|
||||
neutron_l3_agent_status
|
||||
rc=$?
|
||||
if ocf_is_true "$OCF_RESKEY_check_state_reports" ; then
|
||||
if [ $rc -eq 0 ]; then
|
||||
check_local_reports
|
||||
rc=$?
|
||||
fi
|
||||
fi
|
||||
return $rc
|
||||
|
||||
}
|
||||
|
||||
|
||||
neutron_l3_agent_start() {
|
||||
local rc
|
||||
|
||||
neutron_l3_agent_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_SUCCESS ]; then
|
||||
ocf_log info "OpenStack neutron-l3-agent already running"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
clean_up
|
||||
sleep 1
|
||||
clean_up_namespaces
|
||||
rm -f $OCF_RESKEY_state_reports_file
|
||||
|
||||
# run and detach to background agent as daemon.
|
||||
# Don't use ocf_run as we're sending the tool's output to /dev/null
|
||||
su ${OCF_RESKEY_user} -s /bin/sh -c "${OCF_RESKEY_binary} --config-file=$OCF_RESKEY_config \
|
||||
--config-file=$OCF_RESKEY_plugin_config --log-file=$OCF_RESKEY_log_file $OCF_RESKEY_additional_parameters \
|
||||
>> /dev/null"' 2>&1 & echo \$! > $OCF_RESKEY_pid'
|
||||
ocf_log debug "Create pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
|
||||
# Spin waiting for the server to come up.
|
||||
# Let the CRM/LRM time us out if required
|
||||
while true; do
|
||||
neutron_l3_agent_monitor
|
||||
rc=$?
|
||||
[ $rc -eq $OCF_SUCCESS ] && break
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ] ; then
|
||||
ocf_log err "OpenStack neutron-l3-agent start failed"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
if ! ocf_is_true "$OCF_RESKEY_multiple_agents" ; then
|
||||
# detach deferred rescheduling procedure
|
||||
RESCHEDULING_CMD="q-agent-cleanup.py --agent=l3 --reschedule --remove-dead ${AUTH_TAIL} 2>&1 >> /var/log/neutron/rescheduling.log"
|
||||
RESCH_CMD=''
|
||||
for ((i=0; i<$OCF_RESKEY_rescheduling_tries; i++)) ; do
|
||||
RESCH_CMD="$RESCH_CMD sleep $OCF_RESKEY_rescheduling_interval ; $RESCHEDULING_CMD ;"
|
||||
done
|
||||
bash -c "$RESCH_CMD" &
|
||||
fuel-fdb-cleaner --ssh-keyfile /root/.ssh/id_rsa_neutron -l /var/log/neutron/fdb-cleaner.log
|
||||
fi
|
||||
|
||||
ocf_log info "OpenStack L3 agent (neutron-l3-agent) started"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
neutron_l3_agent_stop() {
|
||||
local rc
|
||||
local pid
|
||||
|
||||
neutron_l3_agent_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
clean_up
|
||||
sleep 1
|
||||
clean_up_namespaces
|
||||
ocf_log info "OpenStack L3 agent ($OCF_RESKEY_binary) already stopped"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# Try SIGTERM
|
||||
pid=`get_worker_pid`
|
||||
# stop waiting
|
||||
shutdown_timeout=15
|
||||
iteration_time=3
|
||||
if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
|
||||
shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-6))
|
||||
fi
|
||||
all_inside_ns_pids=`get_pid_list_for_ns_list $(get_ns_list)`
|
||||
all_pids="$pid $all_inside_ns_pids"
|
||||
count=0
|
||||
alive=1
|
||||
while [ $alive -gt 0 ] && [ $count -lt $shutdown_timeout ]; do
|
||||
alive=0
|
||||
ocf_run kill -s TERM $all_pids
|
||||
sleep $iteration_time
|
||||
#Check if processes are alive after command kill
|
||||
#if yes, send to them the term signal again
|
||||
np=""
|
||||
for pid in $all_pids ; do
|
||||
ocf_run kill -s 0 $pid
|
||||
if [ $? -eq 0 ]; then
|
||||
np="$np $pid"
|
||||
((alive++))
|
||||
fi
|
||||
done
|
||||
if [ $alive -gt 0 ] ; then
|
||||
all_pids=$np
|
||||
fi
|
||||
((count+=$iteration_time))
|
||||
ocf_log debug "OpenStack L3 agent ($OCF_RESKEY_binary) still hasn't stopped yet. Waiting ..."
|
||||
done
|
||||
#Send the kill signal to processes which are still alive
|
||||
if [ $alive -gt 0 ] ; then
|
||||
alive=0
|
||||
ocf_run kill -s KILL $all_pids
|
||||
sleep 1
|
||||
for pid in $all_pids ; do
|
||||
ocf_run kill -s 0 $pid
|
||||
if [ $? -eq 0 ]; then
|
||||
((alive++))
|
||||
fi
|
||||
done
|
||||
if [ $alive -gt 0 ] ; then
|
||||
ocf_log err "OpenStack L3 agent (${OCF_RESKEY_binary}) stop failed"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
fi
|
||||
ocf_log info "OpenStack L3 agent ($OCF_RESKEY_binary) stopped"
|
||||
|
||||
ocf_log debug "Delete pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
rm -f $OCF_RESKEY_pid
|
||||
clean_up
|
||||
sleep 1
|
||||
clean_up_namespaces
|
||||
if ! ocf_is_true "$OCF_RESKEY_multiple_agents" ; then
|
||||
q-agent-cleanup.py --agent=l3 --remove-self ${AUTH_TAIL} 2>&1 >> /var/log/neutron/rescheduling.log &
|
||||
fi
|
||||
sleep 3
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
case "$1" in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS;;
|
||||
usage|help) usage
|
||||
exit $OCF_SUCCESS;;
|
||||
esac
|
||||
|
||||
# Anything except meta-data and help must pass validation
|
||||
neutron_l3_agent_validate || exit $?
|
||||
setup_auth || exit $?
|
||||
umask 0022
|
||||
|
||||
# What kind of method was invoked?
|
||||
case "$1" in
|
||||
start) neutron_l3_agent_start;;
|
||||
stop) neutron_l3_agent_stop;;
|
||||
status) neutron_l3_agent_status;;
|
||||
monitor) neutron_l3_agent_monitor;;
|
||||
validate-all) ;;
|
||||
*) usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED;;
|
||||
esac
|
||||
|
366
files/fuel-ha-utils/ocf/ocf-neutron-metadata-agent
Normal file
366
files/fuel-ha-utils/ocf/ocf-neutron-metadata-agent
Normal file
@ -0,0 +1,366 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
#
|
||||
# OpenStack Neutron Metadata Agent service
|
||||
#
|
||||
# Description: Manages an OpenStack Neutron Metadata Agent process as an HA resource
|
||||
#
|
||||
# Authors: Emilien Macchi
|
||||
# Mainly inspired by the Nova Network resource agent written by Emilien Macchi & Sebastien Han
|
||||
#
|
||||
# Support: openstack@lists.launchpad.net
|
||||
# License: Apache Software License (ASL) 2.0
|
||||
#
|
||||
#
|
||||
# See usage() function below for more details ...
|
||||
#
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
#######################################################################
|
||||
|
||||
# Fill in some defaults if no values are specified
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
|
||||
OCF_RESKEY_binary_default="neutron-metadata-agent"
|
||||
OCF_RESKEY_config_default="/etc/neutron/neutron.conf"
|
||||
OCF_RESKEY_agent_config_default="/etc/neutron/metadata_agent.ini"
|
||||
OCF_RESKEY_log_file_default="/var/log/neutron/metadata-agent.log"
|
||||
OCF_RESKEY_user_default="neutron"
|
||||
OCF_RESKEY_pid_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
OCF_RESKEY_debug_default="false"
|
||||
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_agent_config=${OCF_RESKEY_agent_config_default}}
|
||||
: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
: ${OCF_RESKEY_log_file=${OCF_RESKEY_log_file_default}}
|
||||
: ${OCF_RESKEY_debug=${OCF_RESKEY_debug_default}}
|
||||
|
||||
#######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<UEND
|
||||
usage: $0 (start|stop|validate-all|meta-data|status|monitor)
|
||||
|
||||
$0 manages an OpenStack Neutron Metadata Agent (${OCF_RESKEY_binary}) process as an HA resource
|
||||
|
||||
The 'start' operation starts the networking service.
|
||||
The 'stop' operation stops the networking service.
|
||||
The 'validate-all' operation reports whether the parameters are valid
|
||||
The 'meta-data' operation reports this RA's meta-data information
|
||||
The 'status' operation reports whether the networking service is running
|
||||
The 'monitor' operation reports whether the networking service seems to be working
|
||||
|
||||
UEND
|
||||
}
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="neutron-metadata-agent">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
Resource agent for the OpenStack Neutron Metadata Agent
|
||||
May manage a neutron-metadata-agent instance or a clone set that
|
||||
creates a distributed neutron-metadata-agent cluster.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages the OpenStack OVS Service (${OCF_RESKEY_binary})</shortdesc>
|
||||
<parameters>
|
||||
|
||||
<parameter name="binary" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the Neutron Metadata Agent binary
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Neutron Metadata Agent binary</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binary_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack Neutron Service (neutron-server) configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack OVS Server (neutron-server) config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="agent_config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack Neutron Metadata Agent configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Neutron Metadata Agent config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_agent_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="user" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
User running Neutron Metadata Agent service (${OCF_RESKEY_binary})
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Neutron Metadata Agent service (${OCF_RESKEY_binary}) user</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_user_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pid" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The pid file to use for this Neutron Metadata Agent service (${OCF_RESKEY_binary}) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Neutron Metadata Agent service (${OCF_RESKEY_binary}) pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pid_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="log_file" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The log file to use for this OpenStack Metadata Service (${OCF_RESKEY_binary}) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Metadata Service (${OCF_RESKEY_binary}) log file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_log_file_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="debug" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The debug flag for OpenStack Metadata Service (${OCF_RESKEY_binary}) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Metadata Service (${OCF_RESKEY_binary}) debug flag</shortdesc>
|
||||
<content type="boolean" default="${OCF_RESKEY_debug_default}" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20" />
|
||||
<action name="stop" timeout="20" />
|
||||
<action name="status" timeout="20" />
|
||||
<action name="monitor" timeout="30" interval="20" />
|
||||
<action name="validate-all" timeout="5" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
get_worker_pid() {
|
||||
local options
|
||||
local pid
|
||||
# FIXME: Remove if condition and set 'falo' statically once Fuel
|
||||
# discontinue support of Ubuntu 12.04 and CentOs 6.x where -a was not defined.
|
||||
if pgrep -V | awk 'match($0, /[0-9]\.[0-9].*/) {if (substr($0, RSTART, RLENGTH) < 3.3) {exit 1}}'; then
|
||||
options='falo'
|
||||
else
|
||||
options='flo'
|
||||
fi
|
||||
pid=`pgrep -u ${OCF_RESKEY_user} -${options} ${OCF_RESKEY_binary} | awk '/python \/usr\/bin/ {print $1}'`
|
||||
echo $pid
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Functions invoked by resource manager actions
|
||||
|
||||
neutron_metadata_agent_validate() {
|
||||
local rc
|
||||
|
||||
check_binary $OCF_RESKEY_binary
|
||||
check_binary netstat
|
||||
|
||||
# A config file on shared storage that is not available
|
||||
# during probes is OK.
|
||||
if [ ! -f $OCF_RESKEY_config ]; then
|
||||
if ! ocf_is_probe; then
|
||||
ocf_log err "Config $OCF_RESKEY_config doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
ocf_log_warn "Config $OCF_RESKEY_config not available during a probe"
|
||||
fi
|
||||
|
||||
getent passwd $OCF_RESKEY_user >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "User $OCF_RESKEY_user doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
neutron_metadata_agent_status() {
|
||||
local pid
|
||||
local f_pid
|
||||
local rc
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${OCF_RESKEY_pid} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
ocf_log debug "Create pid file dir: ${PID_DIR} and chown to ${OCF_RESKEY_user}"
|
||||
mkdir -p "${PID_DIR}"
|
||||
chown -R ${OCF_RESKEY_user} "${PID_DIR}"
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
pid=`get_worker_pid`
|
||||
if [ "xxx$pid" == "xxx" ] ; then
|
||||
ocf_log warn "OpenStack Neutron agent '$OCF_RESKEY_binary' not running."
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
|
||||
# Check PID file and create if need
|
||||
if [ ! -f $OCF_RESKEY_pid ] ; then
|
||||
ocf_log warn "OpenStack Neutron agent (${OCF_RESKEY_binary}) was run, but no PID file found."
|
||||
ocf_log warn "Writing PID='$pid' to '$OCF_RESKEY_pid' for '${OCF_RESKEY_binary}' worker..."
|
||||
echo $pid > $OCF_RESKEY_pid
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# compare PID from file with PID from `pgrep...`
|
||||
f_pid=`cat $OCF_RESKEY_pid | tr '\n' ' ' | awk '{print $1}'`
|
||||
if [ "xxx$pid" == "xxx$f_pid" ]; then
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# at this point we have PID file and PID from it
|
||||
# defferents with PID from `pgrep...`
|
||||
if [ ! -d "/proc/$f_pid" ] || [ "xxx$f_pid" == "xxx" ] ; then
|
||||
# process with PID from PID-file not found
|
||||
ocf_log warn "Old PID file $OCF_RESKEY_pid found, but no running processes with PID=$f_pid found."
|
||||
ocf_log warn "PID-file will be re-created (with PID=$pid)."
|
||||
echo $pid > $OCF_RESKEY_pid
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# at this point we have alien PID-file and running prosess with this PID.
|
||||
ocf_log warn "Another daemon (with PID=$f_pid) running with PID file '$OCF_RESKEY_pid'. My PID=$pid"
|
||||
return $OCF_ERR_GENERIC
|
||||
}
|
||||
|
||||
|
||||
neutron_metadata_agent_monitor() {
|
||||
neutron_metadata_agent_status
|
||||
rc=$?
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
neutron_metadata_agent_start() {
|
||||
local rc
|
||||
|
||||
neutron_metadata_agent_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_SUCCESS ]; then
|
||||
ocf_log info "OpenStack Neutron Metadata Agent (${OCF_RESKEY_binary}) already running"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# run and detach to background Neutron-metadata-agent as daemon.
|
||||
# Don't use ocf_run as we're sending the tool's output to /dev/null
|
||||
su ${OCF_RESKEY_user} -s /bin/sh -c "${OCF_RESKEY_binary} --config-file=$OCF_RESKEY_config \
|
||||
--config-file=$OCF_RESKEY_agent_config --log-file=$OCF_RESKEY_log_file $OCF_RESKEY_additional_parameters \
|
||||
>> /dev/null"' 2>&1 & echo \$! > $OCF_RESKEY_pid'
|
||||
ocf_log debug "Create pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
|
||||
# Spin waiting for the server to come up.
|
||||
# Let the CRM/LRM time us out if required
|
||||
while true; do
|
||||
neutron_metadata_agent_monitor
|
||||
rc=$?
|
||||
[ $rc -eq $OCF_SUCCESS ] && break
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ] ; then
|
||||
ocf_log err "OpenStack (${OCF_RESKEY_binary}) start failed"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
ocf_log info "OpenStack Neutron Metadata Agent (${OCF_RESKEY_binary}) started"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
|
||||
neutron_metadata_agent_stop() {
|
||||
local rc
|
||||
local pid
|
||||
|
||||
neutron_metadata_agent_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
ocf_log info "OpenStack Neutron Metadata Agent (${OCF_RESKEY_binary}) already stopped"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# Try SIGTERM
|
||||
pid=`get_worker_pid`
|
||||
if [ "xxx$pid" == "xxx" ] ; then
|
||||
ocf_log warn "OpenStack Neutron Metadata Agent (${OCF_RESKEY_binary}) not running."
|
||||
#return $OCF_NOT_RUNNING
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
ocf_run kill -s TERM $pid
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "OpenStack Neutron Metadata Agent (${OCF_RESKEY_binary}) couldn't be stopped"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
# stop waiting
|
||||
shutdown_timeout=15
|
||||
if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
|
||||
shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5))
|
||||
fi
|
||||
count=0
|
||||
while [ $count -lt $shutdown_timeout ]; do
|
||||
neutron_metadata_agent_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
break
|
||||
fi
|
||||
count=`expr $count + 1`
|
||||
sleep 1
|
||||
ocf_log debug "OpenStack Neutron Metadata Agent (${OCF_RESKEY_binary}) still hasn't stopped yet. Waiting ..."
|
||||
done
|
||||
|
||||
neutron_metadata_agent_status
|
||||
rc=$?
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
# SIGTERM didn't help either, try SIGKILL
|
||||
ocf_log info "OpenStack Neutron Metadata Agent (${OCF_RESKEY_binary}) failed to stop after ${shutdown_timeout}s \
|
||||
using SIGTERM. Trying SIGKILL ..."
|
||||
ocf_run kill -s KILL $pid
|
||||
fi
|
||||
|
||||
ocf_log info "OpenStack Neutron Metadata Agent (${OCF_RESKEY_binary}) stopped"
|
||||
|
||||
ocf_log debug "Delete pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
rm -f $OCF_RESKEY_pid
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
case "$1" in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS;;
|
||||
usage|help) usage
|
||||
exit $OCF_SUCCESS;;
|
||||
esac
|
||||
|
||||
# Anything except meta-data and help must pass validation
|
||||
neutron_metadata_agent_validate || exit $?
|
||||
umask 0022
|
||||
|
||||
# What kind of method was invoked?
|
||||
case "$1" in
|
||||
start) neutron_metadata_agent_start;;
|
||||
stop) neutron_metadata_agent_stop;;
|
||||
status) neutron_metadata_agent_status;;
|
||||
monitor) neutron_metadata_agent_monitor;;
|
||||
validate) neutron_metadata_agent_validate;;
|
||||
validate-all) neutron_metadata_agent_validate;;
|
||||
*) usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED;;
|
||||
esac
|
405
files/fuel-ha-utils/ocf/ocf-neutron-ovs-agent
Normal file
405
files/fuel-ha-utils/ocf/ocf-neutron-ovs-agent
Normal file
@ -0,0 +1,405 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
#
|
||||
# OpenStack OVS Service
|
||||
#
|
||||
# Description: Manages an OpenStack OVS Service process as an HA resource
|
||||
#
|
||||
# Authors: Emilien Macchi
|
||||
# Mainly inspired by the Nova Network resource agent written by Emilien Macchi & Sebastien Han
|
||||
#
|
||||
# Support: openstack@lists.launchpad.net
|
||||
# License: Apache Software License (ASL) 2.0
|
||||
#
|
||||
#
|
||||
# See usage() function below for more details ...
|
||||
#
|
||||
# OCF instance parameters:
|
||||
# OCF_RESKEY_binary
|
||||
# OCF_RESKEY_config
|
||||
# OCF_RESKEY_plugin_config
|
||||
# OCF_RESKEY_user
|
||||
# OCF_RESKEY_pid
|
||||
# OCF_RESKEY_amqp_server_port
|
||||
# OCF_RESKEY_additional_parameters
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
#######################################################################
|
||||
|
||||
# Fill in some defaults if no values are specified
|
||||
|
||||
OCF_RESKEY_binary_default="neutron-openvswitch-agent"
|
||||
OCF_RESKEY_config_default="/etc/neutron/neutron.conf"
|
||||
OCF_RESKEY_plugin_config_default="/etc/neutron/plugin.ini"
|
||||
OCF_RESKEY_user_default="neutron"
|
||||
OCF_RESKEY_pid_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
OCF_RESKEY_amqp_server_port_default="5672"
|
||||
OCF_RESKEY_segmentation_bridge_default="br-tun"
|
||||
OCF_RESKEY_log_file_default="/var/log/neutron/openvswitch-agent.log"
|
||||
OCF_RESKEY_debug_default='false'
|
||||
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
: ${OCF_RESKEY_plugin_config=${OCF_RESKEY_plugin_config_default}}
|
||||
: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
: ${OCF_RESKEY_amqp_server_port=${OCF_RESKEY_amqp_server_port_default}}
|
||||
: ${OCF_RESKEY_segmentation_bridge=${OCF_RESKEY_segmentation_bridge_default}}
|
||||
: ${OCF_RESKEY_log_file=${OCF_RESKEY_log_file_default}}
|
||||
: ${OCF_RESKEY_debug=${OCF_RESKEY_debug_default}}
|
||||
|
||||
#######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<UEND
|
||||
usage: $0 (start|stop|validate-all|meta-data|status|monitor)
|
||||
|
||||
$0 manages an OpenStack OVS Service (${OCF_RESKEY_binary}) process as an HA resource
|
||||
|
||||
The 'start' operation starts the networking service.
|
||||
The 'stop' operation stops the networking service.
|
||||
The 'validate-all' operation reports whether the parameters are valid
|
||||
The 'meta-data' operation reports this RA's meta-data information
|
||||
The 'status' operation reports whether the networking service is running
|
||||
The 'monitor' operation reports whether the networking service seems to be working
|
||||
|
||||
UEND
|
||||
}
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="neutron-ovs-agent">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
Resource agent for the OpenStack Neutron OVS Service (${OCF_RESKEY_binary})
|
||||
May manage a neutron-ovs-agent instance or a clone set that
|
||||
creates a distributed neutron-ovs-agent cluster.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Manages the OpenStack OVS Service (${OCF_RESKEY_binary})</shortdesc>
|
||||
<parameters>
|
||||
|
||||
<parameter name="binary" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack OVS agent binary (${OCF_RESKEY_binary})
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack OVS agent binary (${OCF_RESKEY_binary})</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_binary_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack Neutron Service (neutron-server) configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Neutron Server (neutron-server) config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="plugin_config" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Location of the OpenStack OVS agent (${OCF_RESKEY_binary}) configuration file
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack OVS agent (${OCF_RESKEY_binary}) config file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_plugin_config_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="user" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
User running OpenStack OVS Service (${OCF_RESKEY_binary})
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack OVS Service (${OCF_RESKEY_binary}) user</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_user_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="pid" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The pid file to use for this OpenStack OVS Service (${OCF_RESKEY_binary}) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack OVS Service (${OCF_RESKEY_binary}) pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pid_default}" />
|
||||
</parameter>
|
||||
|
||||
|
||||
<parameter name="additional_parameters" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Additional parameters to pass on to the OpenStack OVS Service (${OCF_RESKEY_binary})
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Additional parameters for neutron-ovs-agent</shortdesc>
|
||||
<content type="string" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="segmentation_bridge" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
OVS integration bridge name OpenStack OVS Service (${OCF_RESKEY_binary})
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Segmentation bridge name for neutron-ovs-agent</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_segmentation_bridge_default}"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="log_file" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The log file to use for this OpenStack OVS Service (${OCF_RESKEY_binary}) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack OVS Service (${OCF_RESKEY_binary}) log file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_log_file_default}" />
|
||||
</parameter>
|
||||
|
||||
<parameter name="debug" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The debug flag for OpenStack OVS Service (${OCF_RESKEY_binary}) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Metadata Service (${OCF_RESKEY_binary}) debug flag</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_debug_default}" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20" />
|
||||
<action name="stop" timeout="20" />
|
||||
<action name="status" timeout="20" />
|
||||
<action name="monitor" timeout="30" interval="20" />
|
||||
<action name="validate-all" timeout="5" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
get_worker_pid() {
|
||||
local options
|
||||
local pid
|
||||
# FIXME: Remove if condition and set 'falo' statically once Fuel
|
||||
# discontinue support of Ubuntu 12.04 and CentOs 6.x where -a was not defined.
|
||||
if pgrep -V | awk 'match($0, /[0-9]\.[0-9].*/) {if (substr($0, RSTART, RLENGTH) < 3.3) {exit 1}}'; then
|
||||
options='falo'
|
||||
else
|
||||
options='flo'
|
||||
fi
|
||||
pid=`pgrep -u ${OCF_RESKEY_user} -${options} ${OCF_RESKEY_binary} | awk '/python \/usr\/bin/ {print $1}'`
|
||||
echo $pid
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Functions invoked by resource manager actions
|
||||
|
||||
neutron_ovs_agent_validate() {
|
||||
local rc
|
||||
|
||||
check_binary $OCF_RESKEY_binary
|
||||
check_binary netstat
|
||||
|
||||
# A config file on shared storage that is not available
|
||||
# during probes is OK.
|
||||
if [ ! -f $OCF_RESKEY_config ]; then
|
||||
if ! ocf_is_probe; then
|
||||
ocf_log err "Config $OCF_RESKEY_config doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
ocf_log_warn "Config $OCF_RESKEY_config not available during a probe"
|
||||
fi
|
||||
|
||||
getent passwd $OCF_RESKEY_user >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "User $OCF_RESKEY_user doesn't exist"
|
||||
return $OCF_ERR_INSTALLED
|
||||
fi
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
neutron_ovs_agent_status() {
|
||||
local pid
|
||||
local f_pid
|
||||
local rc
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${OCF_RESKEY_pid} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
ocf_log debug "Create pid file dir: ${PID_DIR} and chown to ${OCF_RESKEY_user}"
|
||||
mkdir -p "${PID_DIR}"
|
||||
chown -R ${OCF_RESKEY_user} "${PID_DIR}"
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
pid=`get_worker_pid`
|
||||
if [ "xxx$pid" == "xxx" ] ; then
|
||||
ocf_log warn "OpenStack Neutron agent '$OCF_RESKEY_binary' not running."
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
#ocf_log debug "PID='$pid'"
|
||||
|
||||
# Check PID file and create if need
|
||||
if [ ! -f $OCF_RESKEY_pid ] ; then
|
||||
ocf_log warn "OpenStack Neutron agent (${OCF_RESKEY_binary}) was run, but no PID file found."
|
||||
ocf_log warn "Writing PID='$pid' to '$OCF_RESKEY_pid' for '${OCF_RESKEY_binary}' worker..."
|
||||
echo $pid > $OCF_RESKEY_pid
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# compare PID from file with PID from `pgrep...`
|
||||
f_pid=`cat $OCF_RESKEY_pid | tr '\n' ' ' | awk '{print $1}'`
|
||||
if [ "xxx$pid" == "xxx$f_pid" ]; then
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# at this point we have PID file and PID from it
|
||||
# defferents with PID from `pgrep...`
|
||||
if [ ! -d "/proc/$f_pid" ] || [ "xxx$f_pid" == "xxx" ] ; then
|
||||
# process with PID from PID-file not found
|
||||
ocf_log warn "Old PID file $OCF_RESKEY_pid found, but no running processes with PID=$f_pid found."
|
||||
ocf_log warn "PID-file will be re-created (with PID=$pid)."
|
||||
echo $pid > $OCF_RESKEY_pid
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# at this point we have alien PID-file and running prosess with this PID.
|
||||
ocf_log warn "Another daemon (with PID=$f_pid) running with PID file '$OCF_RESKEY_pid'. My PID=$pid"
|
||||
return $OCF_ERR_GENERIC
|
||||
}
|
||||
|
||||
|
||||
neutron_ovs_agent_monitor() {
|
||||
neutron_ovs_agent_status
|
||||
rc=$?
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
cleanup_agents_ovs_bridges() {
|
||||
# todo: remove ports, created by agent
|
||||
rc=0
|
||||
}
|
||||
|
||||
|
||||
neutron_ovs_agent_start() {
|
||||
local rc
|
||||
|
||||
neutron_ovs_agent_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_SUCCESS ]; then
|
||||
ocf_log info "OpenStack OVS agent (${OCF_RESKEY_binary}) already running"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
cleanup_agents_ovs_bridges
|
||||
|
||||
# run and detach to background Neutron-ovs-agent as daemon.
|
||||
# Don't use ocf_run as we're sending the tool's output
|
||||
su ${OCF_RESKEY_user} -s /bin/sh -c "${OCF_RESKEY_binary} --config-file=$OCF_RESKEY_config \
|
||||
--config-file=$OCF_RESKEY_plugin_config --log-file=$OCF_RESKEY_log_file $OCF_RESKEY_additional_parameters \
|
||||
>> /dev/null"' 2>&1 & echo \$! > $OCF_RESKEY_pid'
|
||||
ocf_log debug "Create pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
|
||||
# Spin waiting for the server to come up.
|
||||
# Let the CRM/LRM time us out if required
|
||||
while true; do
|
||||
neutron_ovs_agent_monitor
|
||||
rc=$?
|
||||
[ $rc -eq $OCF_SUCCESS ] && break
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "OpenStack (${OCF_RESKEY_binary}) start failed"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
ocf_log info "OpenStack OVS agent (${OCF_RESKEY_binary}) started"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
neutron_ovs_agent_stop() {
|
||||
local rc
|
||||
local pid
|
||||
|
||||
neutron_ovs_agent_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
cleanup_agents_ovs_bridges
|
||||
ocf_log info "OpenStack OVS agent (${OCF_RESKEY_binary}) already stopped"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
# Try SIGTERM
|
||||
|
||||
pid=`get_worker_pid`
|
||||
if [ "xxx$pid" == "xxx" ] ; then
|
||||
ocf_log warn "OpenStack Neutron agent '$OCF_RESKEY_binary' not running."
|
||||
#return $OCF_NOT_RUNNING
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
ocf_run kill -s TERM $pid
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
ocf_log err "OpenStack OVS agent (${OCF_RESKEY_binary}) couldn't be stopped"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
# stop waiting
|
||||
shutdown_timeout=15
|
||||
if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
|
||||
shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5))
|
||||
fi
|
||||
count=0
|
||||
while [ $count -lt $shutdown_timeout ]; do
|
||||
neutron_ovs_agent_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_NOT_RUNNING ]; then
|
||||
break
|
||||
fi
|
||||
count=`expr $count + 1`
|
||||
sleep 1
|
||||
ocf_log debug "OpenStack OVS agent (${OCF_RESKEY_binary}) still hasn't stopped yet. Waiting ..."
|
||||
done
|
||||
|
||||
neutron_ovs_agent_status
|
||||
rc=$?
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
# SIGTERM didn't help either, try SIGKILL
|
||||
ocf_log info "OpenStack OVS agent (${OCF_RESKEY_binary}) failed to stop after ${shutdown_timeout}s \
|
||||
using SIGTERM. Trying SIGKILL ..."
|
||||
ocf_run kill -s KILL $pid
|
||||
fi
|
||||
|
||||
cleanup_agents_ovs_bridges
|
||||
|
||||
ocf_log info "OpenStack OVS agent (${OCF_RESKEY_binary}) stopped"
|
||||
|
||||
ocf_log debug "Delete pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
rm -f $OCF_RESKEY_pid
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
case "$1" in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS;;
|
||||
usage|help) usage
|
||||
exit $OCF_SUCCESS;;
|
||||
esac
|
||||
|
||||
# Anything except meta-data and help must pass validation
|
||||
neutron_ovs_agent_validate || exit $?
|
||||
umask 0022
|
||||
|
||||
# What kind of method was invoked?
|
||||
case "$1" in
|
||||
start) neutron_ovs_agent_start;;
|
||||
stop) neutron_ovs_agent_stop;;
|
||||
status) neutron_ovs_agent_status;;
|
||||
monitor) neutron_ovs_agent_monitor;;
|
||||
validate-all) ;;
|
||||
*) usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED;;
|
||||
esac
|
1384
files/fuel-ha-utils/ocf/rabbitmq
Executable file
1384
files/fuel-ha-utils/ocf/rabbitmq
Executable file
File diff suppressed because it is too large
Load Diff
76
files/fuel-ha-utils/tools/clustercheck
Normal file
76
files/fuel-ha-utils/tools/clustercheck
Normal file
@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script to make a proxy (ie HAProxy) capable of monitoring Percona XtraDB Cluster nodes properly
|
||||
#
|
||||
# Author: Olaf van Zandwijk <olaf.vanzandwijk@nedap.com>
|
||||
# Author: Raghavendra Prabhu <raghavendra.prabhu@percona.com>
|
||||
#
|
||||
# Documentation and download: https://github.com/olafz/percona-clustercheck
|
||||
#
|
||||
# Based on the original script from Unai Rodriguez
|
||||
#
|
||||
|
||||
if [[ $1 == '-h' || $1 == '--help' ]];then
|
||||
echo "Usage: $0 <user> <pass> <available_when_donor=0|1> <log_file> <available_when_readonly=0|1> <defaults_extra_file>"
|
||||
exit
|
||||
fi
|
||||
|
||||
[ -f /etc/wsrepclustercheckrc ] && . /etc/wsrepclustercheckrc
|
||||
|
||||
if [[ -r $DEFAULTS_EXTRA_FILE ]];then
|
||||
MYSQL_CMDLINE="mysql --defaults-extra-file=$DEFAULTS_EXTRA_FILE -nNE --connect-timeout=$TIMEOUT \
|
||||
--user=${MYSQL_USERNAME} --password=${MYSQL_PASSWORD} -h ${MYSQL_HOST} -P ${MYSQL_PORT}"
|
||||
else
|
||||
MYSQL_CMDLINE="mysql -nNE --connect-timeout=$TIMEOUT --user=${MYSQL_USERNAME} --password=${MYSQL_PASSWORD} \
|
||||
-h ${MYSQL_HOST} -P ${MYSQL_PORT}"
|
||||
fi
|
||||
#
|
||||
# Perform the query to check the wsrep_local_state
|
||||
#
|
||||
WSREP_STATUS=$($MYSQL_CMDLINE -e "SHOW STATUS LIKE 'wsrep_local_state';" \
|
||||
2>${ERR_FILE} | tail -1 2>>${ERR_FILE})
|
||||
|
||||
if [[ "${WSREP_STATUS}" == "4" ]] || [[ "${WSREP_STATUS}" == "2" && ${AVAILABLE_WHEN_DONOR} == 1 ]]
|
||||
then
|
||||
# Check only when set to 0 to avoid latency in response.
|
||||
if [[ $AVAILABLE_WHEN_READONLY -eq 0 ]];then
|
||||
READ_ONLY=$($MYSQL_CMDLINE -e "SHOW GLOBAL VARIABLES LIKE 'read_only';" \
|
||||
2>${ERR_FILE} | tail -1 2>>${ERR_FILE})
|
||||
|
||||
if [[ "${READ_ONLY}" == "ON" ]];then
|
||||
# Percona XtraDB Cluster node local state is 'Synced', but it is in
|
||||
# read-only mode. The variable AVAILABLE_WHEN_READONLY is set to 0.
|
||||
# => return HTTP 503
|
||||
# Shell return-code is 1
|
||||
echo -en "HTTP/1.1 503 Service Unavailable\r\n"
|
||||
echo -en "Content-Type: text/plain\r\n"
|
||||
echo -en "Connection: close\r\n"
|
||||
echo -en "Content-Length: 43\r\n"
|
||||
echo -en "\r\n"
|
||||
echo -en "Percona XtraDB Cluster Node is read-only.\r\n"
|
||||
sleep 0.1
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
# Percona XtraDB Cluster node local state is 'Synced' => return HTTP 200
|
||||
# Shell return-code is 0
|
||||
echo -en "HTTP/1.1 200 OK\r\n"
|
||||
echo -en "Content-Type: text/plain\r\n"
|
||||
echo -en "Connection: close\r\n"
|
||||
echo -en "Content-Length: 40\r\n"
|
||||
echo -en "\r\n"
|
||||
echo -en "Percona XtraDB Cluster Node is synced.\r\n"
|
||||
sleep 0.1
|
||||
exit 0
|
||||
else
|
||||
# Percona XtraDB Cluster node local state is not 'Synced' => return HTTP 503
|
||||
# Shell return-code is 1
|
||||
echo -en "HTTP/1.1 503 Service Unavailable\r\n"
|
||||
echo -en "Content-Type: text/plain\r\n"
|
||||
echo -en "Connection: close\r\n"
|
||||
echo -en "Content-Length: 44\r\n"
|
||||
echo -en "\r\n"
|
||||
echo -en "Percona XtraDB Cluster Node is not synced.\r\n"
|
||||
sleep 0.1
|
||||
exit 1
|
||||
fi
|
645
files/fuel-ha-utils/tools/q-agent-cleanup.py
Normal file
645
files/fuel-ha-utils/tools/q-agent-cleanup.py
Normal file
@ -0,0 +1,645 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright 2013 - 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.
|
||||
|
||||
import argparse
|
||||
from ConfigParser import SafeConfigParser
|
||||
import functools
|
||||
import json
|
||||
import logging
|
||||
import logging.config
|
||||
import logging.handlers
|
||||
import re
|
||||
import socket
|
||||
import StringIO
|
||||
import subprocess
|
||||
import sys
|
||||
from time import sleep
|
||||
|
||||
from neutronclient.neutron import client as n_client
|
||||
|
||||
LOG_NAME = 'q-agent-cleanup'
|
||||
|
||||
API_VER = '2.0'
|
||||
PORT_ID_PART_LEN = 11
|
||||
|
||||
|
||||
def make_logger(handler=logging.StreamHandler(sys.stdout), level=logging.INFO):
|
||||
format = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
|
||||
handler.setFormatter(format)
|
||||
logger = logging.getLogger(LOG_NAME)
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(level)
|
||||
return logger
|
||||
|
||||
LOG = make_logger()
|
||||
|
||||
AUTH_KEYS = {
|
||||
'tenant_name': 'admin_tenant_name',
|
||||
'username': 'admin_user',
|
||||
'password': 'admin_password',
|
||||
'auth_url': 'auth_uri',
|
||||
}
|
||||
|
||||
|
||||
def get_auth_data(cfg_file, section='keystone_authtoken', keys=AUTH_KEYS):
|
||||
cfg = SafeConfigParser()
|
||||
with open(cfg_file) as f:
|
||||
cfg.readfp(f)
|
||||
auth_data = {}
|
||||
for key, value in keys.iteritems():
|
||||
auth_data[key] = cfg.get(section, value)
|
||||
return auth_data
|
||||
|
||||
# Note(xarses): be careful not to inject \n's into the regex pattern
|
||||
# or it will case the maching to fail
|
||||
RECOVERABLE = re.compile((
|
||||
'(HTTP\s+400\))|'
|
||||
'(400-\{\'message\'\:\s+\'\'\})|'
|
||||
'(\[Errno 111\]\s+Connection\s+refused)|'
|
||||
'(503\s+Service\s+Unavailable)|'
|
||||
'(504\s+Gateway\s+Time-out)|'
|
||||
'(\:\s+Maximum\s+attempts\s+reached)|'
|
||||
'(Unauthorized\:\s+bad\s+credentials)|'
|
||||
'(Max\s+retries\s+exceeded)|'
|
||||
"""('*NoneType'*\s+object\s+ha'\s+no\s+attribute\s+'*__getitem__'*$)|"""
|
||||
'(No\s+route\s+to\s+host$)|'
|
||||
'(Lost\s+connection\s+to\s+MySQL\s+server)'), flags=re.M)
|
||||
|
||||
RETRY_COUNT = 50
|
||||
RETRY_DELAY = 2
|
||||
|
||||
|
||||
def retry(func, pattern=RECOVERABLE):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
i = 0
|
||||
while True:
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
if pattern and not pattern.match(e.message):
|
||||
raise e
|
||||
i += 1
|
||||
if i >= RETRY_COUNT:
|
||||
raise e
|
||||
print("retry request {0}: {1}".format(i, e))
|
||||
sleep(RETRY_DELAY)
|
||||
return wrapper
|
||||
|
||||
|
||||
class NeutronCleaner(object):
|
||||
PORT_NAME_PREFIXES_BY_DEV_OWNER = {
|
||||
'network:dhcp': 'tap',
|
||||
'network:router_gateway': 'qg-',
|
||||
'network:router_interface': 'qr-',
|
||||
}
|
||||
PORT_NAME_PREFIXES = {
|
||||
# contains tuples of prefixes
|
||||
'dhcp': (PORT_NAME_PREFIXES_BY_DEV_OWNER['network:dhcp'],),
|
||||
'l3': (
|
||||
PORT_NAME_PREFIXES_BY_DEV_OWNER['network:router_gateway'],
|
||||
PORT_NAME_PREFIXES_BY_DEV_OWNER['network:router_interface']
|
||||
)
|
||||
}
|
||||
BRIDGES_FOR_PORTS_BY_AGENT = {
|
||||
'dhcp': ('br-int',),
|
||||
'l3': ('br-int', 'br-ex'),
|
||||
}
|
||||
PORT_OWNER_PREFIXES = {
|
||||
'dhcp': ('network:dhcp',),
|
||||
'l3': ('network:router_gateway', 'network:router_interface')
|
||||
}
|
||||
NS_NAME_PREFIXES = {
|
||||
'dhcp': 'qdhcp',
|
||||
'l3': 'qrouter',
|
||||
}
|
||||
AGENT_BINARY_NAME = {
|
||||
'dhcp': 'neutron-dhcp-agent',
|
||||
'l3': 'neutron-l3-agent',
|
||||
'ovs': 'neutron-openvswitch-agent'
|
||||
}
|
||||
|
||||
CMD__list_ovs_port = ['ovs-vsctl', 'list-ports']
|
||||
CMD__remove_ovs_port = ['ovs-vsctl', '--', '--if-exists', 'del-port']
|
||||
CMD__remove_ip_addr = ['ip', 'address', 'delete']
|
||||
CMD__ip_netns_list = ['ip', 'netns', 'list']
|
||||
CMD__ip_netns_exec = ['ip', 'netns', 'exec']
|
||||
|
||||
# 14: tap-xxxyyyzzz:
|
||||
RE__port_in_portlist = re.compile(r"^\s*\d+\:\s+([\w-]+)\:")
|
||||
|
||||
def __init__(self, options, log=None):
|
||||
self.log = log
|
||||
self.auth_data = get_auth_data(cfg_file=options.get('authconf'))
|
||||
self.options = options
|
||||
self.agents = {}
|
||||
self.debug = options.get('debug')
|
||||
self.RESCHEDULING_CALLS = {
|
||||
'dhcp': self._reschedule_agent_dhcp,
|
||||
'l3': self._reschedule_agent_l3,
|
||||
}
|
||||
|
||||
self._client = None
|
||||
|
||||
@property
|
||||
@retry
|
||||
def client(self):
|
||||
if self._client is None:
|
||||
self._client = n_client.Client(API_VER, **self.auth_data)
|
||||
return self._client
|
||||
|
||||
@retry
|
||||
def _get_agents(self, use_cache=True):
|
||||
return self.client.list_agents()['agents']
|
||||
|
||||
@retry
|
||||
def _get_routers(self, use_cache=True):
|
||||
return self.client.list_routers()['routers']
|
||||
|
||||
@retry
|
||||
def _get_networks(self, use_cache=True):
|
||||
return self.client.list_networks()['networks']
|
||||
|
||||
@retry
|
||||
def _list_networks_on_dhcp_agent(self, agent_id):
|
||||
return self.client.list_networks_on_dhcp_agent(
|
||||
agent_id)['networks']
|
||||
|
||||
@retry
|
||||
def _list_routers_on_l3_agent(self, agent_id):
|
||||
return self.client.list_routers_on_l3_agent(
|
||||
agent_id)['routers']
|
||||
|
||||
@retry
|
||||
def _list_l3_agents_on_router(self, router_id):
|
||||
return self.client.list_l3_agent_hosting_routers(
|
||||
router_id)['agents']
|
||||
|
||||
@retry
|
||||
def _list_dhcp_agents_on_network(self, network_id):
|
||||
return self.client.list_dhcp_agent_hosting_networks(
|
||||
network_id)['agents']
|
||||
|
||||
def _list_orphaned_networks(self):
|
||||
networks = self._get_networks()
|
||||
self.log.debug(
|
||||
"_list_orphaned_networks:, got list of networks {0}".format(
|
||||
json.dumps(networks, indent=4)))
|
||||
orphaned_networks = []
|
||||
for network in networks:
|
||||
if len(self._list_dhcp_agents_on_network(network['id'])) == 0:
|
||||
orphaned_networks.append(network['id'])
|
||||
self.log.debug(
|
||||
"_list_orphaned_networks:, got list of orphaned networks {0}".
|
||||
format(orphaned_networks))
|
||||
return orphaned_networks
|
||||
|
||||
def _list_orphaned_routers(self):
|
||||
routers = self._get_routers()
|
||||
self.log.debug(
|
||||
"_list_orphaned_routers:, got list of routers {0}".format(
|
||||
json.dumps(routers, indent=4)))
|
||||
orphaned_routers = []
|
||||
for router in routers:
|
||||
if len(self._list_l3_agents_on_router(router['id'])) == 0:
|
||||
orphaned_routers.append(router['id'])
|
||||
self.log.debug(
|
||||
"_list_orphaned_routers:, got list of orphaned routers {0}".format(
|
||||
orphaned_routers))
|
||||
return orphaned_routers
|
||||
|
||||
@retry
|
||||
def _add_network_to_dhcp_agent(self, agent_id, net_id):
|
||||
return self.client.add_network_to_dhcp_agent(
|
||||
agent_id, {"network_id": net_id})
|
||||
|
||||
@retry
|
||||
def _add_router_to_l3_agent(self, agent_id, router_id):
|
||||
return self.client.add_router_to_l3_agent(
|
||||
agent_id, {"router_id": router_id})
|
||||
|
||||
@retry
|
||||
def _remove_router_from_l3_agent(self, agent_id, router_id):
|
||||
return self.client.remove_router_from_l3_agent(
|
||||
agent_id, router_id)
|
||||
|
||||
@retry
|
||||
def _delete_agent(self, agent_id):
|
||||
return self.client.delete_agent(agent_id)
|
||||
|
||||
def _get_agents_by_type(self, agent, use_cache=True):
|
||||
self.log.debug("_get_agents_by_type: start.")
|
||||
rv = self.agents.get(agent, []) if use_cache else []
|
||||
if not rv:
|
||||
agents = self._get_agents(use_cache=use_cache)
|
||||
for i in agents:
|
||||
if i['binary'] == self.AGENT_BINARY_NAME.get(agent):
|
||||
rv.append(i)
|
||||
from_cache = ''
|
||||
else:
|
||||
from_cache = ' from local cache'
|
||||
self.log.debug(
|
||||
"_get_agents_by_type: end, {0} rv: {1}".format(
|
||||
from_cache, json.dumps(rv, indent=4)))
|
||||
return rv
|
||||
|
||||
def __collect_namespaces_for_agent(self, agent):
|
||||
cmd = self.CMD__ip_netns_list[:]
|
||||
self.log.debug("Execute command '{0}'".format(' '.join(cmd)))
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
shell=False,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
rc = process.wait()
|
||||
if rc != 0:
|
||||
self.log.error(
|
||||
"ERROR (rc={0}) while execution {1}".format(
|
||||
rc, ' '.join(cmd)))
|
||||
return []
|
||||
# filter namespaces by given agent type
|
||||
netns = []
|
||||
stdout = process.communicate()[0]
|
||||
for ns in StringIO.StringIO(stdout):
|
||||
ns = ns.strip()
|
||||
self.log.debug("Found network namespace '{0}'".format(ns))
|
||||
if ns.startswith(self.NS_NAME_PREFIXES[agent]):
|
||||
netns.append(ns)
|
||||
return netns
|
||||
|
||||
def __collect_ports_for_namespace(self, ns):
|
||||
cmd = self.CMD__ip_netns_exec[:]
|
||||
cmd.extend([ns, 'ip', 'l', 'show'])
|
||||
self.log.debug("Execute command '{0}'".format(' '.join(cmd)))
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
shell=False,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
rc = process.wait()
|
||||
if rc != 0:
|
||||
self.log.error(
|
||||
"ERROR (rc={0}) while execution {1}".format(
|
||||
rc, ' '.join(cmd)))
|
||||
return []
|
||||
ports = []
|
||||
stdout = process.communicate()[0]
|
||||
for line in StringIO.StringIO(stdout):
|
||||
pp = self.RE__port_in_portlist.match(line)
|
||||
if not pp:
|
||||
continue
|
||||
port = pp.group(1)
|
||||
if port != 'lo':
|
||||
self.log.debug("Found port '{0}'".format(port))
|
||||
ports.append(port)
|
||||
return ports
|
||||
|
||||
def _cleanup_ports(self, agent):
|
||||
self.log.debug("_cleanup_ports: start.")
|
||||
|
||||
# get namespaces list
|
||||
netns = self.__collect_namespaces_for_agent(agent)
|
||||
|
||||
# collect ports from namespace
|
||||
ports = []
|
||||
for ns in netns:
|
||||
ports.extend(self.__collect_ports_for_namespace(ns))
|
||||
|
||||
# iterate by port_list and remove port from OVS
|
||||
for port in ports:
|
||||
cmd = self.CMD__remove_ovs_port[:]
|
||||
cmd.append(port)
|
||||
if self.options.get('noop'):
|
||||
self.log.info("NOOP-execution: '{0}'".format(' '.join(cmd)))
|
||||
else:
|
||||
self.log.debug("Execute command '{0}'".format(' '.join(cmd)))
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
shell=False,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
rc = process.wait()
|
||||
if rc != 0:
|
||||
self.log.error(
|
||||
"ERROR (rc={0}) while execution {1}".format(
|
||||
rc, ' '.join(cmd)))
|
||||
self.log.debug("_cleanup_ports: end.")
|
||||
|
||||
return True
|
||||
|
||||
def _reschedule_agent_dhcp(self, agent_type):
|
||||
self.log.debug("_reschedule_agent_dhcp: start.")
|
||||
agents = {
|
||||
'alive': [],
|
||||
'dead': []
|
||||
}
|
||||
# collect networklist from dead DHCP-agents
|
||||
dead_networks = []
|
||||
for agent in self._get_agents_by_type(agent_type):
|
||||
if agent['alive']:
|
||||
self.log.info(
|
||||
"found alive DHCP agent: {0}".format(agent['id']))
|
||||
agents['alive'].append(agent)
|
||||
else:
|
||||
# dead agent
|
||||
self.log.info(
|
||||
"found dead DHCP agent: {0}".format(agent['id']))
|
||||
agents['dead'].append(agent)
|
||||
for net in self._list_networks_on_dhcp_agent(agent['id']):
|
||||
dead_networks.append(net)
|
||||
|
||||
if dead_networks and agents['alive']:
|
||||
# get network-ID list of already attached to alive agent networks
|
||||
lucky_ids = set()
|
||||
map(
|
||||
lambda net: lucky_ids.add(net['id']),
|
||||
self._list_networks_on_dhcp_agent(agents['alive'][0]['id'])
|
||||
)
|
||||
# add dead networks to alive agent
|
||||
for net in dead_networks:
|
||||
if net['id'] not in lucky_ids:
|
||||
# attach network to agent
|
||||
self.log.info(
|
||||
"attach network {net} to DHCP agent {agent}".format(
|
||||
net=net['id'],
|
||||
agent=agents['alive'][0]['id']))
|
||||
if not self.options.get('noop'):
|
||||
self._add_network_to_dhcp_agent(
|
||||
agents['alive'][0]['id'], net['id'])
|
||||
|
||||
# remove dead agents if need (and if found alive agent)
|
||||
if self.options.get('remove-dead'):
|
||||
for agent in agents['dead']:
|
||||
self.log.info(
|
||||
"remove dead DHCP agent: {0}".format(agent['id']))
|
||||
if not self.options.get('noop'):
|
||||
self._delete_agent(agent['id'])
|
||||
orphaned_networks = self._list_orphaned_networks()
|
||||
self.log.info("_reschedule_agent_dhcp: rescheduling orphaned networks")
|
||||
if orphaned_networks and agents['alive']:
|
||||
for network in orphaned_networks:
|
||||
self.log.info(
|
||||
"_reschedule_agent_dhcp: rescheduling {0} to {1}".format(
|
||||
network, agents['alive'][0]['id']))
|
||||
if not self.options.get('noop'):
|
||||
self._add_network_to_dhcp_agent(
|
||||
agents['alive'][0]['id'], network)
|
||||
self.log.info(
|
||||
"_reschedule_agent_dhcp: ended rescheduling of orphaned networks")
|
||||
self.log.debug("_reschedule_agent_dhcp: end.")
|
||||
|
||||
def _reschedule_agent_l3(self, agent_type):
|
||||
self.log.debug("_reschedule_agent_l3: start.")
|
||||
agents = {
|
||||
'alive': [],
|
||||
'dead': []
|
||||
}
|
||||
# collect router-list from dead DHCP-agents
|
||||
dead_routers = [] # array of tuples (router, agentID)
|
||||
for agent in self._get_agents_by_type(agent_type):
|
||||
if agent['alive']:
|
||||
self.log.info("found alive L3 agent: {0}".format(agent['id']))
|
||||
agents['alive'].append(agent)
|
||||
else:
|
||||
# dead agent
|
||||
self.log.info("found dead L3 agent: {0}".format(agent['id']))
|
||||
agents['dead'].append(agent)
|
||||
map(
|
||||
lambda rou: dead_routers.append((rou, agent['id'])),
|
||||
self._list_routers_on_l3_agent(agent['id'])
|
||||
)
|
||||
self.log.debug(
|
||||
"L3 agents in cluster: {0}".format(
|
||||
json.dumps(agents, indent=4)))
|
||||
self.log.debug("Routers, attached to dead L3 agents: {0}".format(
|
||||
json.dumps(dead_routers, indent=4)))
|
||||
|
||||
if dead_routers and agents['alive']:
|
||||
# get router-ID list of already attached to alive agent routerss
|
||||
lucky_ids = set()
|
||||
map(
|
||||
lambda rou: lucky_ids.add(rou['id']),
|
||||
self._list_routers_on_l3_agent(agents['alive'][0]['id'])
|
||||
)
|
||||
# remove dead agents after rescheduling
|
||||
for agent in agents['dead']:
|
||||
self.log.info("remove dead L3 agent: {0}".format(agent['id']))
|
||||
if not self.options.get('noop'):
|
||||
self._delete_agent(agent['id'])
|
||||
# move routers from dead to alive agent
|
||||
for rou in filter(
|
||||
lambda rr: not(rr[0]['id'] in lucky_ids), dead_routers):
|
||||
self.log.info(
|
||||
"schedule router {0} to L3 agent {1}".format(
|
||||
rou[0]['id'],
|
||||
agents['alive'][0]['id']))
|
||||
if not self.options.get('noop'):
|
||||
self._add_router_to_l3_agent(
|
||||
agents['alive'][0]['id'], rou[0]['id'])
|
||||
|
||||
orphaned_routers = self._list_orphaned_routers()
|
||||
self.log.info("_reschedule_agent_l3: rescheduling orphaned routers")
|
||||
if orphaned_routers and agents['alive']:
|
||||
for router in orphaned_routers:
|
||||
self.log.info(
|
||||
"_reschedule_agent_l3: rescheduling {0} to {1}".format(
|
||||
router, agents['alive'][0]['id']))
|
||||
if not self.options.get('noop'):
|
||||
self._add_router_to_l3_agent(
|
||||
agents['alive'][0]['id'], router)
|
||||
self.log.info(
|
||||
"_reschedule_agent_l3: ended rescheduling of orphaned routers")
|
||||
self.log.debug("_reschedule_agent_l3: end.")
|
||||
|
||||
def _remove_self(self, agent_type):
|
||||
self.log.debug("_remove_self: start.")
|
||||
for agent in self._get_agents_by_type(agent_type):
|
||||
if agent['host'] == socket.gethostname():
|
||||
self.log.info(
|
||||
"_remove_self: deleting our own agent {0} of type {1}".
|
||||
format(agent['id'], agent_type))
|
||||
if not self.options.get('noop'):
|
||||
self._delete_agent(agent['id'])
|
||||
self.log.debug("_remove_self: end.")
|
||||
|
||||
def _reschedule_agent(self, agent):
|
||||
self.log.debug("_reschedule_agents: start.")
|
||||
task = self.RESCHEDULING_CALLS.get(agent, None)
|
||||
if task:
|
||||
task(agent)
|
||||
self.log.debug("_reschedule_agents: end.")
|
||||
|
||||
def do(self, agent):
|
||||
if self.options.get('cleanup-ports'):
|
||||
self._cleanup_ports(agent)
|
||||
if self.options.get('reschedule'):
|
||||
self._reschedule_agent(agent)
|
||||
if self.options.get('remove-self'):
|
||||
self._remove_self(agent)
|
||||
|
||||
def _test_healthy(self, agent_list, hostname):
|
||||
rv = False
|
||||
for agent in agent_list:
|
||||
if agent['host'] == hostname and agent['alive']:
|
||||
return True
|
||||
return rv
|
||||
|
||||
def test_healthy(self, agent_type):
|
||||
# OCF_FAILED_MASTER,
|
||||
# http://www.linux-ha.org/doc/dev-guides/_literal_ocf_failed_master_literal_9.html
|
||||
|
||||
rc = 9
|
||||
agentlist = self._get_agents_by_type(agent_type)
|
||||
for hostname in self.options.get('test-hostnames'):
|
||||
if self._test_healthy(agentlist, hostname):
|
||||
return 0
|
||||
return rc
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Neutron network node cleaning tool.')
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--auth-config",
|
||||
dest="authconf",
|
||||
default="/etc/neutron/neutron.conf",
|
||||
help="Read authconfig from service file",
|
||||
metavar="FILE")
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--auth-token",
|
||||
dest="auth-token",
|
||||
default=None,
|
||||
help="Authenticating token (instead username/passwd)",
|
||||
metavar="TOKEN")
|
||||
parser.add_argument(
|
||||
"-u",
|
||||
"--admin-auth-url",
|
||||
dest="admin-auth-url",
|
||||
default=None,
|
||||
help="Authenticating URL (admin)",
|
||||
metavar="URL")
|
||||
parser.add_argument(
|
||||
"--retries",
|
||||
dest="retries",
|
||||
type=int,
|
||||
default=50,
|
||||
help="try NN retries for API call",
|
||||
metavar="NN")
|
||||
parser.add_argument(
|
||||
"--sleep",
|
||||
dest="sleep",
|
||||
type=int,
|
||||
default=2,
|
||||
help="sleep seconds between retries",
|
||||
metavar="SEC")
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--agent",
|
||||
dest="agent",
|
||||
action="append",
|
||||
help="specyfy agents for cleaning",
|
||||
required=True)
|
||||
parser.add_argument(
|
||||
"--cleanup-ports",
|
||||
dest="cleanup-ports",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="cleanup ports for given agents on this node")
|
||||
parser.add_argument(
|
||||
"--remove-self",
|
||||
dest="remove-self",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="remove ourselves from agent list")
|
||||
parser.add_argument(
|
||||
"--activeonly",
|
||||
dest="activeonly",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="cleanup only active ports")
|
||||
parser.add_argument(
|
||||
"--reschedule",
|
||||
dest="reschedule",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="reschedule given agents")
|
||||
parser.add_argument(
|
||||
"--remove-dead",
|
||||
dest="remove-dead",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="remove dead agents while rescheduling")
|
||||
parser.add_argument(
|
||||
"--test-alive-for-hostname",
|
||||
dest="test-hostnames",
|
||||
action="append",
|
||||
help="testing agent's healthy for given hostname")
|
||||
parser.add_argument(
|
||||
"--external-bridge",
|
||||
dest="external-bridge",
|
||||
default="br-ex",
|
||||
help="external bridge name",
|
||||
metavar="IFACE")
|
||||
parser.add_argument(
|
||||
"--integration-bridge",
|
||||
dest="integration-bridge",
|
||||
default="br-int",
|
||||
help="integration bridge name",
|
||||
metavar="IFACE")
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--log",
|
||||
dest="log",
|
||||
action="store",
|
||||
help="log to file instead of STDOUT")
|
||||
parser.add_argument(
|
||||
"--noop",
|
||||
dest="noop",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="do not execute, print to log instead")
|
||||
parser.add_argument(
|
||||
"--debug",
|
||||
dest="debug",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="debug")
|
||||
args = parser.parse_args()
|
||||
RETRY_COUNT = args.retries
|
||||
RETRY_DELAY = args.sleep
|
||||
|
||||
# setup logging
|
||||
if args.log:
|
||||
LOG = make_logger(
|
||||
handler=logging.handlers.WatchedFileHandler(args.log))
|
||||
|
||||
if args.debug:
|
||||
LOG.setLevel(logging.DEBUG)
|
||||
|
||||
LOG.info("Started: {0}".format(' '.join(sys.argv)))
|
||||
cleaner = NeutronCleaner(options=vars(args), log=LOG)
|
||||
rc = 0
|
||||
if vars(args).get('test-hostnames'):
|
||||
rc = cleaner.test_healthy(args.agent[0])
|
||||
else:
|
||||
for i in args.agent:
|
||||
cleaner.do(i)
|
||||
LOG.debug("End.")
|
||||
sys.exit(rc)
|
12
files/fuel-ha-utils/tools/wsrepclustercheckrc
Normal file
12
files/fuel-ha-utils/tools/wsrepclustercheckrc
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
MYSQL_USERNAME="clustercheck"
|
||||
MYSQL_PASSWORD="status"
|
||||
MYSQL_HOST="127.0.0.1"
|
||||
MYSQL_PORT="3307"
|
||||
AVAILABLE_WHEN_DONOR=${3:-1}
|
||||
ERR_FILE="${4:-/dev/null}"
|
||||
AVAILABLE_WHEN_READONLY=${5:-1}
|
||||
DEFAULTS_EXTRA_FILE=${6:-/etc/my.cnf}
|
||||
|
||||
#Timeout exists for instances where mysqld may be hung
|
||||
TIMEOUT=10
|
5
files/fuel-misc/centos_ifdown-local
Normal file
5
files/fuel-misc/centos_ifdown-local
Normal file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
SCRIPT="/etc/sysconfig/network-scripts/interface-down-script-$1"
|
||||
if [[ -x $SCRIPT ]] ; then
|
||||
. $SCRIPT
|
||||
fi
|
5
files/fuel-misc/centos_ifup-local
Normal file
5
files/fuel-misc/centos_ifup-local
Normal file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
SCRIPT="/etc/sysconfig/network-scripts/interface-up-script-$1"
|
||||
if [[ -x $SCRIPT ]] ; then
|
||||
. $SCRIPT
|
||||
fi
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
show_stats() {
|
||||
echo 'show stat' | socat 'UNIX-CONNECT:<%= @haproxy_socket %>' STDIO | awk \
|
||||
echo 'show stat' | socat 'UNIX-CONNECT:/var/lib/haproxy/stats' STDIO | awk \
|
||||
'
|
||||
function fillstr(string, num)
|
||||
{
|
168
specs/fuel-library6.1.spec
Normal file
168
specs/fuel-library6.1.spec
Normal file
@ -0,0 +1,168 @@
|
||||
Summary: Fuel-Library: a set of deployment manifests of Fuel for OpenStack
|
||||
Name: fuel-library6.1
|
||||
#FIXME(aglarendil): this is a temp change for scripts compatibility. Should be bumped everywhere
|
||||
Version: 6.0.0
|
||||
Release: 1
|
||||
Group: System Environment/Libraries
|
||||
License: GPLv2
|
||||
URL: http://github.com/stackforge/fuel-library
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
Provides: fuel-library
|
||||
BuildArch: noarch
|
||||
BuildRoot: %{_tmppath}/fuel-library-%{version}-%{release}
|
||||
|
||||
%define files_source %{_builddir}/%{name}-%{version}/files
|
||||
%define dockerctl_source %{files_source}/fuel-docker-utils
|
||||
%define openstack_version 2014.2-6.1
|
||||
|
||||
%description
|
||||
|
||||
Fuel is the Ultimate Do-it-Yourself Kit for OpenStack
|
||||
Purpose built to assimilate the hard-won experience of our services team, it contains the tooling, information, and support you need to accelerate time to production with OpenStack cloud. OpenStack is a very versatile and flexible cloud management platform. By exposing its portfolio of cloud infrastructure services – compute, storage, networking and other core resources — through ReST APIs, it enables a wide range of control over these services, both from the perspective of an integrated Infrastructure as a Service (IaaS) controlled by applications, as well as automated manipulation of the infrastructure itself. This architectural flexibility doesn’t set itself up magically; it asks you, the user and cloud administrator, to organize and manage a large array of configuration options. Consequently, getting the most out of your OpenStack cloud over time – in terms of flexibility, scalability, and manageability – requires a thoughtful combination of automation and configuration choices.
|
||||
|
||||
This package contains deployment manifests and code to execute provisioning of master and slave nodes.
|
||||
|
||||
%prep
|
||||
%setup -cq
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}/etc/puppet/%{openstack_version}/modules/
|
||||
mkdir -p %{buildroot}/etc/puppet/%{openstack_version}/manifests/
|
||||
mkdir -p %{buildroot}/etc/profile.d/
|
||||
mkdir -p %{buildroot}/etc/dockerctl
|
||||
mkdir -p %{buildroot}/usr/bin/
|
||||
mkdir -p %{buildroot}/usr/lib/
|
||||
mkdir -p %{buildroot}/usr/share/dockerctl
|
||||
mkdir -p %{buildroot}/sbin/
|
||||
cp -fr %{_builddir}/%{name}-%{version}/deployment/puppet/* %{buildroot}/etc/puppet/%{openstack_version}/modules/
|
||||
#FUEL DOCKERCTL UTILITY
|
||||
install -m 0644 %{dockerctl_source}/dockerctl-alias.sh %{buildroot}/etc/profile.d/dockerctl.sh
|
||||
install -m 0755 %{dockerctl_source}/dockerctl %{buildroot}/usr/bin
|
||||
install -m 0755 %{dockerctl_source}/get_service_credentials.py %{buildroot}/usr/bin
|
||||
install -m 0644 %{dockerctl_source}/dockerctl_config %{buildroot}/etc/dockerctl/config
|
||||
install -m 0644 %{dockerctl_source}/functions.sh %{buildroot}/usr/share/dockerctl/
|
||||
#fuel-misc
|
||||
install -m 0755 %{files_source}/fuel-misc/centos_ifdown-local %{buildroot}/sbin/ifup-local
|
||||
install -m 0755 %{files_source}/fuel-misc/centos_ifup-local %{buildroot}/sbin/ifdown-local
|
||||
install -m 0755 %{files_source}/fuel-misc/haproxy-status.sh %{buildroot}/usr/bin/haproxy-status
|
||||
#fuel-ha-utils
|
||||
install -d -m 0755 %{buildroot}/usr/lib/ocf/resource.d/fuel
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/ns_haproxy %{buildroot}/usr/lib/ocf/resource.d/fuel/ns_haproxy
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/mysql-wss %{buildroot}/usr/lib/ocf/resource.d/fuel/mysql-wss
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/ns_dns %{buildroot}/usr/lib/ocf/resource.d/fuel/ns_dns
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/heat_engine_centos %{buildroot}/usr/lib/ocf/resource.d/fuel/heat-engine
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/ns_ntp %{buildroot}/usr/lib/ocf/resource.d/fuel/ns_ntp
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/ocf-neutron-ovs-agent %{buildroot}/usr/lib/ocf/resource.d/fuel/ocf-neutron-ovs-agent
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/ocf-neutron-metadata-agent %{buildroot}/usr/lib/ocf/resource.d/fuel/ocf-neutron-metadata-agent
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/ocf-neutron-dhcp-agent %{buildroot}/usr/lib/ocf/resource.d/fuel/ocf-neutron-dhcp-agent
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/ocf-neutron-l3-agent %{buildroot}/usr/lib/ocf/resource.d/fuel/ocf-neutron-l3-agent
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/rabbitmq %{buildroot}/usr/lib/ocf/resource.d/fuel/rabbitmq-server
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/ns_IPaddr2 %{buildroot}/usr/lib/ocf/resource.d/fuel/ns_IPaddr2
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/ceilometer-agent-central %{buildroot}/usr/lib/ocf/resource.d/fuel/ceilometer-agent-central
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/ocf/ceilometer-alarm-evaluator %{buildroot}/usr/lib/ocf/resource.d/fuel/ceilometer-alarm-evaluator
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/tools/q-agent-cleanup.py %{buildroot}/usr/bin/q-agent-cleanup.py
|
||||
install -m 0755 %{files_source}/fuel-ha-utils/tools/clustercheck %{buildroot}/usr/bin/clustercheck
|
||||
install -m 0644 %{files_source}/fuel-ha-utils/tools/wsrepclustercheckrc %{buildroot}/etc/wsrepclustercheckrc
|
||||
#FIXME - may be we need to put this also into packages
|
||||
#install -m 0755 TEMPLATE /usr/local/bin/puppet-pull
|
||||
#install -m 0755 -d deployment/puppet/sahara/templates /usr/share/sahara/templates
|
||||
#install -m 0755 deployment/puppet/sahara/create_templates.sh /usr/share/sahara/templates/create_templates.sh
|
||||
#install -m 0755 TEMPLATE /usr/local/bin/swift-rings-rebalance.sh
|
||||
#install -m 0755 TEMPLATE /usr/local/bin/swift-rings-sync.sh
|
||||
|
||||
%post -p /bin/bash
|
||||
#Update puppet manifests symlinks to the latest version
|
||||
for i in modules manifests
|
||||
do
|
||||
if [ -L /etc/puppet/${i} ]
|
||||
then
|
||||
unlink /etc/puppet/${i}
|
||||
elif [ -d /etc/puppet/${i} ]
|
||||
then
|
||||
mv /etc/puppet/${i} /etc/puppet/${i}.old
|
||||
fi
|
||||
ln -s /etc/puppet/%{openstack_version}/${i} /etc/puppet/${i}
|
||||
done
|
||||
|
||||
%files
|
||||
/etc/puppet/%{openstack_version}/modules/
|
||||
/etc/puppet/%{openstack_version}/manifests/
|
||||
|
||||
%package -n fuel-dockerctl
|
||||
Summary: Fuel project utilities for Docker container management tool
|
||||
Version: 6.1
|
||||
Release: 1
|
||||
Group: System Environment/Libraries
|
||||
License: GPLv2
|
||||
Provides: fuel-docker-utils
|
||||
URL: http://github.com/stackforge/fuel-library
|
||||
BuildArch: noarch
|
||||
BuildRoot: %{_tmppath}/fuel-library-%{version}-%{release}
|
||||
|
||||
%description -n fuel-dockerctl
|
||||
This package contains a set of helpers to manage docker containers
|
||||
during Fuel All-in-One deployment toolkit installation
|
||||
|
||||
%files -n fuel-dockerctl
|
||||
/etc/profile.d/dockerctl.sh
|
||||
/usr/bin/dockerctl
|
||||
/usr/bin/get_service_credentials.py
|
||||
/usr/share/dockerctl/functions.sh
|
||||
%config(noreplace) /etc/dockerctl/config
|
||||
|
||||
%package -n fuel-misc
|
||||
Summary: Fuel project misc utilities
|
||||
Version: 6.1
|
||||
Release: 1
|
||||
Group: System Environment/Libraries
|
||||
License: Apache 2.0
|
||||
URL: http://github.com/stackforge/fuel-library
|
||||
BuildArch: noarch
|
||||
BuildRoot: %{_tmppath}/fuel-library-%{version}-%{release}
|
||||
|
||||
%description -n fuel-misc
|
||||
A set of scripts for Fuel deployment utility
|
||||
For further information go to http://wiki.openstack.org/Fuel
|
||||
|
||||
%files -n fuel-misc
|
||||
|
||||
#fuel-misc
|
||||
%defattr(-,root,root)
|
||||
/sbin/ifup-local
|
||||
/sbin/ifdown-local
|
||||
/usr/bin/haproxy-status
|
||||
|
||||
%package -n fuel-ha-utils
|
||||
Summary: Fuel project HA utilities
|
||||
Version: 6.1
|
||||
Release: 1
|
||||
Group: System Environment/Libraries
|
||||
# FIXME(aglarendil): mixed license actually - need to figure out the best option
|
||||
License: GPLv2
|
||||
Requires: python-keystoneclient
|
||||
Requires: python-neutronclient
|
||||
URL: http://github.com/stackforge/fuel-library
|
||||
BuildArch: noarch
|
||||
BuildRoot: %{_tmppath}/fuel-library-%{version}-%{release}
|
||||
|
||||
%description -n fuel-ha-utils
|
||||
A set of scripts for Fuel deployment utility HA deployment
|
||||
For further information go to http://wiki.openstack.org/Fuel
|
||||
|
||||
%files -n fuel-ha-utils
|
||||
%defattr(-,root,root)
|
||||
/usr/lib/ocf/resource.d/fuel
|
||||
/usr/bin/q-agent-cleanup.py
|
||||
/usr/bin/clustercheck
|
||||
%config(noreplace) /etc/wsrepclustercheckrc
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf ${buildroot}
|
||||
|
||||
%changelog
|
||||
* Tue Sep 10 2013 Vladimir Kuklin <vkuklin@mirantis.com> - 6.1
|
||||
- Create spec
|
Loading…
Reference in New Issue
Block a user