diff --git a/SOURCES/NovaCompute.patch b/SOURCES/NovaCompute.patch new file mode 100644 index 0000000..8db2532 --- /dev/null +++ b/SOURCES/NovaCompute.patch @@ -0,0 +1,418 @@ +From bd60deaa906cc5fe1cd46549b1318d2b940395ef Mon Sep 17 00:00:00 2001 +From: David Vossel <dvossel@redhat.com> +Date: Thu, 11 Jun 2015 08:41:50 -0500 +Subject: [PATCH] NovaCompute agent + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 4 + + heartbeat/NovaCompute | 363 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 368 insertions(+) + create mode 100644 heartbeat/NovaCompute + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 653e818..69acf3a 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -73,6 +73,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_MailTo.7 \ + ocf_heartbeat_ManageRAID.7 \ + ocf_heartbeat_ManageVE.7 \ ++ ocf_heartbeat_NovaCompute.7 \ + ocf_heartbeat_Pure-FTPd.7 \ + ocf_heartbeat_Raid1.7 \ + ocf_heartbeat_Route.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index e4ed4fd..b77c589 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -29,6 +29,8 @@ halibdir = $(libexecdir)/heartbeat + + ocfdir = $(OCF_RA_DIR_PREFIX)/heartbeat + ++ospdir = $(OCF_RA_DIR_PREFIX)/openstack ++ + dtddir = $(datadir)/$(PACKAGE_NAME) + dtd_DATA = ra-api-1.dtd + +@@ -50,6 +52,8 @@ send_ua_SOURCES = send_ua.c IPv6addr_utils.c + IPv6addr_LDADD = -lplumb $(LIBNETLIBS) + send_ua_LDADD = $(LIBNETLIBS) + ++osp_SCRIPTS = NovaCompute ++ + ocf_SCRIPTS = ClusterMon \ + CTDB \ + Dummy \ +diff --git a/heartbeat/NovaCompute b/heartbeat/NovaCompute +new file mode 100644 +index 0000000..f71abeb +--- /dev/null ++++ b/heartbeat/NovaCompute +@@ -0,0 +1,363 @@ ++#!/bin/sh ++# ++# ++# NovaCompute agent manages compute daemons. ++# ++# Copyright (c) 2015 ++# ++# 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_ACTION=$1} ++ ++####################################################################### ++ ++meta_data() { ++ cat <<END ++<?xml version="1.0"?> ++<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> ++<resource-agent name="NovaCompute" version="1.0"> ++<version>1.0</version> ++ ++<longdesc lang="en"> ++OpenStack Nova Compute Server. ++</longdesc> ++<shortdesc lang="en">OpenStack Nova Compute Server</shortdesc> ++ ++<parameters> ++ ++<parameter name="auth_url" unique="0" required="1"> ++<longdesc lang="en"> ++Authorization URL for connecting to keystone in admin context ++</longdesc> ++<shortdesc lang="en">Authorization URL</shortdesc> ++<content type="string" default="" /> ++</parameter> ++ ++<parameter name="username" unique="0" required="1"> ++<longdesc lang="en"> ++Username for connecting to keystone in admin context ++</longdesc> ++<shortdesc lang="en">Username</shortdesc> ++</parameter> ++ ++<parameter name="password" unique="0" required="1"> ++<longdesc lang="en"> ++Password for connecting to keystone in admin context ++</longdesc> ++<shortdesc lang="en">Password</shortdesc> ++<content type="string" default="" /> ++</parameter> ++ ++<parameter name="tenant_name" unique="0" required="1"> ++<longdesc lang="en"> ++Tenant name for connecting to keystone in admin context. ++Note that with Keystone V3 tenant names are only unique within a domain. ++</longdesc> ++<shortdesc lang="en">Tenant name</shortdesc> ++<content type="string" default="" /> ++</parameter> ++ ++<parameter name="domain" unique="0" required="0"> ++<longdesc lang="en"> ++DNS domain in which hosts live, useful when the cluster uses short names and nova uses FQDN ++</longdesc> ++<shortdesc lang="en">DNS domain</shortdesc> ++<content type="string" default="" /> ++</parameter> ++ ++<parameter name="endpoint_type" unique="0" required="0"> ++<longdesc lang="en"> ++Nova API location (internal, public or admin URL) ++</longdesc> ++<shortdesc lang="en">Nova API location (internal, public or admin URL)</shortdesc> ++<content type="string" default="" /> ++</parameter> ++ ++<parameter name="no_shared_storage" unique="0" required="0"> ++<longdesc lang="en"> ++Disable shared storage recovery for instances. Use at your own risk! ++</longdesc> ++<shortdesc lang="en">Disable shared storage recovery for instances</shortdesc> ++<content type="boolean" default="0" /> ++</parameter> ++ ++</parameters> ++ ++<actions> ++<action name="start" timeout="120" /> ++<action name="stop" timeout="300" /> ++<action name="monitor" timeout="20" interval="10" depth="0"/> ++<action name="validate-all" timeout="20" /> ++<action name="meta-data" timeout="5" /> ++<action name="notify" timeout="600" /> ++</actions> ++</resource-agent> ++END ++} ++ ++####################################################################### ++ ++# don't exit on TERM, to test that lrmd makes sure that we do exit ++trap sigterm_handler TERM ++sigterm_handler() { ++ ocf_log info "They use TERM to bring us down. No such luck." ++ return ++} ++ ++nova_usage() { ++ cat <<END ++usage: $0 {start|stop|monitor|notify|validate-all|meta-data} ++ ++Expects to have a fully populated OCF RA-compliant environment set. ++END ++} ++ ++nova_pid() { ++ ps axf | grep python.*nova-compute | grep -v grep | awk '{print $1}' ++} ++ ++nova_start() { ++ nova_monitor ++ if [ $? = $OCF_SUCCESS ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ export LIBGUESTFS_ATTACH_METHOD=appliance ++ su nova -s /bin/sh -c /usr/bin/nova-compute & ++ ++ rc=$OCF_NOT_RUNNING ++ ocf_log info "Waiting for nova to start" ++ while [ $rc != $OCF_SUCCESS ]; do ++ nova_monitor ++ rc=$? ++ done ++ ++## TEMPORARY disable call to "service enable" that seems to create ++## issues and it is unnecessary since fence_compute doesn't disable ++## the service ++ ++# if [ "x${OCF_RESKEY_domain}" != x ]; then ++# export service_host="${NOVA_HOST}.${OCF_RESKEY_domain}" ++# else ++# export service_host="${NOVA_HOST}" ++# fi ++ ++# python -c "import os; from novaclient import client as nova_client; nova = nova_client.Client('2', os.environ.get('OCF_RESKEY_username'), os.environ.get('OCF_RESKEY_password'), os.environ.get('OCF_RESKEY_tenant_name'), os.environ.get('OCF_RESKEY_auth_url')); nova.services.enable(os.environ.get('service_host'), 'nova-compute');" ++ ++# rc=$? ++# if [ $rc != 0 ]; then ++# ocf_exit_reason "nova.services.enable failed $rc" ++# exit $OCF_NOT_RUNNING ++# fi ++ ++ return $OCF_SUCCESS ++} ++ ++nova_stop() { ++ pid=$(nova_pid) ++ if [ "x$pid" != x ]; then ++ su nova -c "kill -TERM $pid" -s /bin/bash ++ fi ++ ++ while [ "x$pid" != x ]; do ++ sleep 1 ++ pid=$(nova_pid) ++ done ++ ++ return $OCF_SUCCESS ++} ++ ++nova_monitor() { ++ pid=$(nova_pid) ++ if [ "x$pid" != x ]; then ++ ## TEMPORARY disable call to fence_compute to avoid noise on first ++ ## first startup due to nova-compute not being fast enough to populate ++ ## the db and fence_compute checking if node exists and it's enabled ++ #state=$(fence_compute ${fence_options} -o status -n $NOVA_HOST | grep Status) ++ #if [ "x$state" = "xStatus: ON" ]; then ++ return $OCF_SUCCESS ++ #else ++ # ocf_exit_reason "Nova status: $state" ++ # return $OCF_ERR_GENERIC ++ #fi ++ fi ++ ++ return $OCF_NOT_RUNNING ++} ++ ++nova_notify() { ++ if [ "x${OCF_RESKEY_CRM_meta_notify_operation}" != "xstop" ]; then ++ return $OCF_SUCCESS ++ elif [ "x${OCF_RESKEY_CRM_meta_notify_type}" != "xpost" ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ # Only the first node not stopping performs evacuates for now ++ # Can we allow all of them to do it? It would make this block much simpler. ++ for host in ${OCF_RESKEY_CRM_meta_notify_active_uname}; do ++ for stop in ${OCF_RESKEY_CRM_meta_notify_stop_uname}; do ++ if [ "$stop" = "$host" ]; then ++ : $host is one of the nodes that is stopping ++ ++ elif [ "x$(echo ${host} | awk -F. '{print $1}')" != "x$(uname -n | awk -F. '{print $1}')" ]; then ++ : We are not the first non-stopping node ++ return $OCF_SUCCESS ++ ++ else ++ # Also repeat for any peer NOT in active_uname somehow? ++ for node in $OCF_RESKEY_CRM_meta_notify_stop_uname; do ++ ocf_log info "Performing evacuations for $node" ++ fence_compute ${fence_options} -o reboot -n $node ++ done ++ return $OCF_SUCCESS ++ fi ++ done ++ done ++} ++ ++nova_validate() { ++ rc=$OCF_SUCCESS ++ fence_options="" ++ ++ check_binary openstack-config ++ check_binary fence_compute ++ check_binary nova-compute ++ ++ if [ ! -f /etc/nova/nova.conf ]; then ++ ocf_exit_reason "/etc/nova/nova.conf not found" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ if [ -z "${OCF_RESKEY_auth_url}" ]; then ++ ocf_exit_reason "auth_url not configured" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ fence_options="${fence_options} -k ${OCF_RESKEY_auth_url}" ++ ++ if [ -z "${OCF_RESKEY_username}" ]; then ++ ocf_exit_reason "username not configured" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ fence_options="${fence_options} -l ${OCF_RESKEY_username}" ++ ++ if [ -z "${OCF_RESKEY_password}" ]; then ++ ocf_exit_reason "password not configured" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ fence_options="${fence_options} -p ${OCF_RESKEY_password}" ++ ++ if [ -z "${OCF_RESKEY_tenant_name}" ]; then ++ ocf_exit_reason "tenant_name not configured" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ fence_options="${fence_options} -t ${OCF_RESKEY_tenant_name}" ++ ++ if [ -n "${OCF_RESKEY_domain}" ]; then ++ fence_options="${fence_options} -d ${OCF_RESKEY_domain}" ++ fi ++ ++ if [ -n "${OCF_RESKEY_no_shared_storage}" ]; then ++ if ocf_is_true "${OCF_RESKEY_no_shared_storage}"; then ++ fence_options="${fence_options} --no-shared-storage" ++ fi ++ fi ++ ++ if [ -n "${OCF_RESKEY_endpoint_type}" ]; then ++ case ${OCF_RESKEY_endpoint_type} in ++ adminURL|publicURL|internalURL) ;; ++ *) ++ ocf_exit_reason "endpoint_type ${OCF_RESKEY_endpoint_type} not valid. Use adminURL or publicURL or internalURL" ++ exit $OCF_ERR_CONFIGURED ++ ;; ++ esac ++ fence_options="${fence_options} -e ${OCF_RESKEY_endpoint_type}" ++ fi ++ ++ # we take a chance here and hope that host is either not configured ++ # or configured in nova.conf ++ ++ NOVA_HOST=$(openstack-config --get /etc/nova/nova.conf DEFAULT host 2>/dev/null) ++ if [ $? = 1 ]; then ++ if [ "x${OCF_RESKEY_domain}" != x ]; then ++ NOVA_HOST=$(uname -n | awk -F. '{print $1}') ++ else ++ NOVA_HOST=$(uname -n) ++ fi ++ fi ++ ++ # We only need to check a configured value, calculated ones are fine ++ openstack-config --get /etc/nova/nova.conf DEFAULT host 2>/dev/null ++ if [ $? = 0 ]; then ++ if [ "x${OCF_RESKEY_domain}" != x ]; then ++ short_host=$(uname -n | awk -F. '{print $1}') ++ if [ "x$NOVA_HOST" != "x${short_host}" ]; then ++ ocf_exit_reason "Invalid Nova host name, must be ${short_host} in order for instance recovery to function" ++ rc=$OCF_ERR_CONFIGURED ++ fi ++ ++ elif [ "x$NOVA_HOST" != "x$(uname -n)" ]; then ++ ocf_exit_reason "Invalid Nova host name, must be $(uname -n) in order for instance recovery to function" ++ rc=$OCF_ERR_CONFIGURED ++ fi ++ fi ++ ++ if [ $rc != $OCF_SUCCESS ]; then ++ exit $rc ++ fi ++ return $rc ++} ++ ++case $__OCF_ACTION in ++meta-data) meta_data ++ exit $OCF_SUCCESS ++ ;; ++usage|help) nova_usage ++ exit $OCF_SUCCESS ++ ;; ++esac ++ ++nova_validate ++ ++case $__OCF_ACTION in ++start) nova_start;; ++stop) nova_stop;; ++monitor) nova_monitor;; ++notify) nova_notify;; ++validate-all) exit $OCF_SUCCESS;; ++*) nova_usage ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac ++rc=$? ++ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" ++exit $rc +-- +1.8.4.2 + diff --git a/SPECS/resource-agents.spec b/SPECS/resource-agents.spec index 2416df5..bb77695 100644 --- a/SPECS/resource-agents.spec +++ b/SPECS/resource-agents.spec @@ -32,7 +32,7 @@ Name: resource-agents Summary: Open Source HA Reusable Cluster Resource Scripts Version: 3.9.5 -Release: 40%{?dist}.3 +Release: 40%{?dist}.4 License: GPLv2+ and LGPLv2+ URL: https://github.com/ClusterLabs/resource-agents %if 0%{?fedora} || 0%{?centos_version} || 0%{?rhel} @@ -101,6 +101,7 @@ Patch56: bz1135026-docker-handle-invalid-monitor-cmd.patch Patch57: bz1118029-iscsi-remove-write-back.patch Patch58: rabbitmq-cluster.patch Patch59: bz1189187-redis-agent.patch +Patch60: NovaCompute.patch Obsoletes: heartbeat-resources <= %{version} Provides: heartbeat-resources = %{version} @@ -248,6 +249,7 @@ exit 1 %patch57 -p1 %patch58 -p1 %patch59 -p1 +%patch60 -p1 %build if [ ! -f configure ]; then @@ -260,6 +262,7 @@ chmod 755 heartbeat/nfsnotify chmod 755 heartbeat/docker chmod 755 heartbeat/rabbitmq-cluster chmod 755 heartbeat/redis +chmod 755 heartbeat/NovaCompute %if 0%{?fedora} >= 11 || 0%{?centos_version} > 5 || 0%{?rhel} > 5 CFLAGS="$(echo '%{optflags}')" @@ -338,6 +341,7 @@ rm -rf %{buildroot} /usr/lib/ocf/lib/heartbeat /usr/lib/ocf/resource.d/heartbeat +/usr/lib/ocf/resource.d/openstack %if %{with rgmanager} /usr/lib/ocf/resource.d/redhat %endif @@ -493,6 +497,11 @@ ccs_update_schema > /dev/null 2>&1 ||: %changelog +* Thu Jun 11 2015 David Vossel <dvossel@redhat.com> - 3.9.5-40.4 +- Support for NovaCompute resource-agent + + Resolves: rhbz#1229383 + * Thu Feb 5 2015 David Vossel <dvossel@redhat.com> - 3.9.5-40.3 - Support for redis resource-agent