#!/bin/sh # # # OpenStack Bare Metal Provisioning Service Conductor Service (ironic-conductor) # # Description: Manages an OpenStack Bare Metal Provisioning Service Conductor Service (ironic-conductor) 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 # # Copyright (c) 2017 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-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 # OCF_RESKEY_tftproot ####################################################################### # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs . /usr/bin/tsconfig ####################################################################### # Fill in some defaults if no values are specified OCF_RESKEY_binary_default="ironic-conductor" OCF_RESKEY_config_default="/etc/ironic/ironic.conf" OCF_RESKEY_user_default="root" OCF_RESKEY_pid_default="$HA_RSCTMP/$OCF_RESOURCE_INSTANCE.pid" OCF_RESKEY_amqp_server_port_default="5672" OCF_RESKEY_tftproot_default="/opt/cgcs/ironic/" : ${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}} : ${OCF_RESKEY_tftproot=${OCF_RESKEY_tftproot_default}} ####################################################################### usage() { cat < 1.0 Resource agent for the OpenStack Bare Metal Provisioning Service Conductor Service (ironic-conductor) May manage a ironic-conductor instance or a clone set that creates a distributed ironic-conductor cluster. Manages the OpenStack Bare Metal Provisioning Service Conductor Service (ironic-conductor) Location of the OpenStack Bare Metal Provisioning Service Conductor server binary (ironic-conductor) OpenStack Bare Metal Provisioning Service Conductor server binary (ironic-conductor) Location of the OpenStack Bare Metal Provisioning Service Conductor Service (ironic-conductor) configuration file OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor registry) config file User running OpenStack Bare Metal Provisioning Service Conductor Service (ironic-conductor) OpenStack Bare Metal Provisioning Service Conductor Service (ironic-conductor) user The pid file to use for this OpenStack Bare Metal Provisioning Service Conductor Service (ironic-conductor) instance OpenStack Bare Metal Provisioning Service Conductor Service (ironic-conductor) pid file The listening port number of the AMQP server. Use for monitoring purposes AMQP listening port Additional parameters to pass on to the OpenStack Bare Metal Provisioning Service Conductor Service (ironic-conductor) Additional parameters for ironic-conductor TFTP root directory to copy the base tftp files to OpenStack Bare Metal Provisioning Service TFTP root END } ####################################################################### # Functions invoked by resource manager actions ironic_conductor_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 } ironic_conductor_validate() { local rc check_binary $OCF_RESKEY_binary check_binary netstat ironic_conductor_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 } ironic_conductor_status() { local pid local rc if [ ! -f $OCF_RESKEY_pid ]; then ocf_log info "OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor) is not running" return $OCF_NOT_RUNNING else pid=`cat $OCF_RESKEY_pid` fi ocf_run -warn kill -s 0 $pid rc=$? if [ $rc -eq 0 ]; then return $OCF_SUCCESS else ocf_log info "Old PID file found, but OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor) is not running" rm -f $OCF_RESKEY_pid return $OCF_NOT_RUNNING fi } ironic_conductor_monitor() { local rc local pid local scheduler_amqp_check ironic_conductor_status rc=$? # If status returned anything but success, return that immediately if [ $rc -ne $OCF_SUCCESS ]; then return $rc fi ocf_log debug "OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor) monitor succeeded" return $OCF_SUCCESS } ironic_conductor_start() { local rc ironic_conductor_status rc=$? if [ $rc -eq $OCF_SUCCESS ]; then ocf_log info "OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor) already running" return $OCF_SUCCESS fi # copy tftp server required files: pxelinux.0 and chain.c32 rsync -c \ /usr/share/syslinux/pxelinux.0 \ /usr/share/syslinux/chain.c32 \ ${OCF_RESKEY_tftproot}/ chown ironic ${OCF_RESKEY_tftproot}/pxelinux.0 ${OCF_RESKEY_tftproot}/chain.c32 # run the actual ironic-conductor 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 # Spin waiting for the server to come up. while true; do ironic_conductor_monitor rc=$? [ $rc -eq $OCF_SUCCESS ] && break if [ $rc -ne $OCF_NOT_RUNNING ]; then ocf_log err "OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor) start failed" exit $OCF_ERR_GENERIC fi sleep 1 done ocf_log info "OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor) started" return $OCF_SUCCESS } ironic_conductor_confirm_stop() { local my_bin local my_processes my_binary=`which ${OCF_RESKEY_binary}` my_processes=`pgrep -l -f "^(python|/usr/bin/python|/usr/bin/python2) ${my_binary}([^\w-]|$)"` if [ -n "${my_processes}" ] then ocf_log info "About to SIGKILL the following: ${my_processes}" pkill -KILL -f "^(python|/usr/bin/python|/usr/bin/python2) ${my_binary}([^\w-]|$)" fi } ironic_conductor_stop() { local rc local pid ironic_conductor_status rc=$? if [ $rc -eq $OCF_NOT_RUNNING ]; then ocf_log info "OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor) already stopped" ironic_conductor_confirm_stop 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 Bare Metal Provisioning Service Conductor (ironic-conductor) couldn't be stopped" ironic_conductor_confirm_stop exit $OCF_ERR_GENERIC fi # stop waiting shutdown_timeout=2 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 ironic_conductor_status rc=$? if [ $rc -eq $OCF_NOT_RUNNING ]; then break fi count=`expr $count + 1` sleep 1 ocf_log debug "OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor) still hasn't stopped yet. Waiting ..." done ironic_conductor_status rc=$? if [ $rc -ne $OCF_NOT_RUNNING ]; then # SIGTERM didn't help either, try SIGKILL ocf_log info "OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor) failed to stop after ${shutdown_timeout}s \ using SIGTERM. Trying SIGKILL ..." ocf_run kill -s KILL $pid fi ironic_conductor_confirm_stop ocf_log info "OpenStack Bare Metal Provisioning Service Conductor (ironic-conductor) stopped" 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 ironic_conductor_validate || exit $? # What kind of method was invoked? case "$1" in start) ironic_conductor_start;; stop) ironic_conductor_stop;; status) ironic_conductor_status;; monitor) ironic_conductor_monitor;; validate-all) ;; *) usage exit $OCF_ERR_UNIMPLEMENTED;; esac