Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[openstack agents] Volume re-attaching, v3 API, get hostname from corosync #1228

Merged
merged 11 commits into from Jun 7, 2019
201 changes: 172 additions & 29 deletions heartbeat/openstack-cinder-volume
Expand Up @@ -27,7 +27,6 @@
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#


#######################################################################
# Initialization:

Expand All @@ -36,8 +35,14 @@

# Defaults
OCF_RESKEY_openstackcli_default="/usr/bin/openstack"
OCF_RESKEY_node_id_cache_file_default="/tmp/node_id"
OCF_RESKEY_volume_local_check_default="true"

export attached_server_id=""

: ${OCF_RESKEY_openstackcli=${OCF_RESKEY_openstackcli_default}}
: ${OCF_RESKEY_node_id_cache_file=${OCF_RESKEY_node_id_cache_file_default}}
: ${OCF_RESKEY_volume_local_check=${OCF_RESKEY_volume_local_check_default}}

#######################################################################

Expand Down Expand Up @@ -74,6 +79,26 @@ Path to command line tools for openstack.
<content type="string" default="${OCF_RESKEY_openstackcli_default}" />
</parameter>

<parameter name="node_id_cache_file">
<longdesc lang="en">
Path to Node ID cache file, used to avoid Openstack API calls:
1. Is the local file written?
2. Is openstack_id available as a node attribute?
3. Can we get it from the API?
</longdesc>
<shortdesc lang="en">Path to Node ID cache file</shortdesc>
<content type="string" default="${OCF_RESKEY_node_id_cache_file_default}" />
</parameter>

<parameter name="volume_local_check">
<longdesc lang="en">
This option allows the cluster to monitor the cinder volume presence without
calling the API.
</longdesc>
<shortdesc lang="en">Monitor cinder volume locally</shortdesc>
<content type="boolean" default="${OCF_RESKEY_volume_local_check_default}" />
</parameter>

<parameter name="openrc" required="1">
<longdesc lang="en">
Valid Openstack credentials as openrc file from api_access/openrc.
Expand Down Expand Up @@ -103,8 +128,82 @@ Cinder volume identifier to use to attach the bloc storage.
END
}

#
# This is used to get the node ID from different sources:
# 1. Is the local file written?
# 2. Is openstack_id available as a node attribute?
# 3. Can we get it from the API?
#
# When the ID is retrieved, the local cache file is written.
# This prevents the agent to call the API each time the agent is used.
#
_get_node_id() {
local crm_node
local node
local node_id
local result

crm_node=$(crm_node -n)

#
# Use local cache
#
if [ -f $OCF_RESKEY_node_id_cache_file ] ; then
node_id=$(cat $OCF_RESKEY_node_id_cache_file)

if [ ! -z "$node_id" ] ; then
echo $node_id
return
fi
fi

#
# Query the attributes database
#
node_id=$(${HA_SBIN_DIR}/attrd_updater --query -n openstack_id -N $crm_node \
| tr ' ' '\n' \
| awk -F= '/value=/ {gsub("\"","");print $NF}')

if [ ! -z "$node_id" ] ; then
echo $node_id | awk '{print $1}'
echo $node_id | awk '{print $1}' > $OCF_RESKEY_node_id_cache_file
return
fi

#
# Use the API
#
node=$(crm_node -n | awk -F. '{print $1}')

result=$($OCF_RESKEY_openstackcli server list \
--format value --column ID --column Name \
| grep $node)

if [ $? -eq 0 ] ; then
echo $result | awk '{print $1}'
echo $result | awk '{print $1}' > $OCF_RESKEY_node_id_cache_file
return
fi

ocf_exit_reason "openstack_id attribute must be set for node $crm_node"
return $OCF_ERR_CONFIGURED
}

osvol_validate() {
local node_id

check_binary "$OCF_RESKEY_openstackcli"
check_binary "awk"
check_binary "tr"

. $OCF_RESKEY_openrc

node_id=$(_get_node_id)

if [ -z "$node_id" ] ; then
ocf_exit_reason "openstack_id attribute must be set for node $crm_node"
return $OCF_ERR_CONFIGURED
fi

if [ -z "$OCF_RESKEY_openrc" ]; then
ocf_exit_reason "openrc parameter not set"
Expand All @@ -116,39 +215,58 @@ osvol_validate() {
return $OCF_ERR_CONFIGURED
fi

. $OCF_RESKEY_openrc

if ! $OCF_RESKEY_openstackcli volume list|grep -q $OCF_RESKEY_volume_id ; then
ocf_exit_reason "Volume $OCF_RESKEY_volume_id not found"
return $OCF_ERR_CONFIGURED
fi

return $OCF_SUCCESS
}

osvol_monitor() {
local result
local attached_server_id
local node_id
local short_volume_id
local fdisk_command

if ocf_is_true $OCF_RESKEY_volume_local_check ; then
#
# Is the volue attached?
# We check the local devices
#
short_volume_id=$(echo $OCF_RESKEY_volume_id | awk '{print substr($0, 0, 20)}')
if uname | grep -q Linux ; then
fdisk_command="fdisk -l"
else
fdisk_command="fdisk"
fi

# Is the volue attached?
result=$($OCF_RESKEY_openstackcli volume show \
--column status \
--column attachments \
--format value \
$OCF_RESKEY_volume_id)

if [[ "$result" =~ "available" ]] ; then
ocf_log warn "$OCF_RESKEY_volume_id is not attached to any instance"
return $OCF_NOT_RUNNING
$fdisk_command /dev/disk/by-id/virtio-$short_volume_id 1>/dev/null 2>&1
if [ $? -eq 0 ] ; then
return $OCF_SUCCESS
else
ocf_log warn "$OCF_RESKEY_volume_id is not attached to instance $(_get_node_id)"
return $OCF_NOT_RUNNING
fi
else
attached_server_id=$(echo $result|head -n1|awk -F "'" '{print $4}')
ocf_log info "$OCF_RESKEY_volume_id is attached to instance $attached_server_id"
node_id=$(${HA_SBIN_DIR}/attrd_updater --query -n openstack_id -N $HOSTNAME \
| awk '{gsub("value=","") ; gsub("\"","") ; print $NF}')

if [ "$node_id" != "$attached_server_id" ] ; then
#
# Is the volue attached?
# We use the API
#
result=$($OCF_RESKEY_openstackcli volume show \
--column status \
--column attachments \
--format value \
$OCF_RESKEY_volume_id)

if echo "$result" | grep -q available ; then
ocf_log warn "$OCF_RESKEY_volume_id is not attached to any instance"
return $OCF_NOT_RUNNING
else
export attached_server_id=$(echo $result|head -n1|awk -F "'" '{print $4}')
ocf_log info "$OCF_RESKEY_volume_id is attached to instance $attached_server_id"

# Compare node_id and the id of the node the volume is attached to
node_id=$(_get_node_id)

if [ "$node_id" != "$attached_server_id" ] ; then
return $OCF_NOT_RUNNING
fi
fi
fi

Expand All @@ -158,14 +276,20 @@ osvol_monitor() {
osvol_stop() {
local node_id

#
# Is the volume already attached?
#
osvol_monitor
if [ $? = $OCF_NOT_RUNNING ]; then
ocf_log info "Volume $OCF_RESKEY_volume_id already available"
return $OCF_SUCCESS
fi

node_id=$(${HA_SBIN_DIR}/attrd_updater --query -n openstack_id -N $HOSTNAME \
| awk '{gsub("value=","") ; gsub("\"","") ; print $NF}')
node_id=$(_get_node_id)

#
# Unmout the volume
#
if ! $OCF_RESKEY_openstackcli server remove volume $node_id $OCF_RESKEY_volume_id ; then
ocf_log error "Couldn't remove volume $OCF_RESKEY_volume_id from instance $node_id"
return $OCF_ERR_GENERIC
Expand All @@ -178,14 +302,33 @@ osvol_stop() {
osvol_start() {
local node_id

#
# Is the volume already attached?
#
osvol_monitor
if [ $? = $OCF_SUCCESS ]; then
ocf_log info "$OCF_RESKEY_volume_id already attached"
return $OCF_SUCCESS
fi

node_id=$(${HA_SBIN_DIR}/attrd_updater --query -n openstack_id -N $HOSTNAME \
| awk '{gsub("value=","") ; gsub("\"","") ; print $NF}')
#
# Unmout it from another node
# TODO: make it optional in case multi-attachment is allowed by Cinder
#
if [ ! -z $attached_server_id ] ; then
if ! $OCF_RESKEY_openstackcli server remove volume $attached_server_id $OCF_RESKEY_volume_id ; then
ocf_log error "Couldn't remove volume $OCF_RESKEY_volume_id from instance $attached_server_id"
return $OCF_ERR_GENERIC
fi
fi

export attached_server_id=""

node_id=$(_get_node_id)

#
# Attach the volume
#
$OCF_RESKEY_openstackcli server add volume $node_id $OCF_RESKEY_volume_id
if [ $? != $OCF_SUCCESS ]; then
ocf_log error "Couldn't add volume $OCF_RESKEY_volume_id to instance $node_id"
Expand Down
18 changes: 12 additions & 6 deletions heartbeat/openstack-floating-ip
Expand Up @@ -132,7 +132,7 @@ osflip_validate() {
return $OCF_ERR_CONFIGURED
fi

${HA_SBIN_DIR}/attrd_updater --query -n openstack_ports -N $HOSTNAME > /dev/null 2>&1
${HA_SBIN_DIR}/attrd_updater --query -n openstack_ports -N $(crm_node -n) > /dev/null 2>&1
if [ $? -ne 0 ] ; then
ocf_log warn "attr_updater failed to get openstack_ports attribute of node $OCF_RESOURCE_INSTANCE"
return $OCF_ERR_GENERIC
Expand All @@ -147,8 +147,10 @@ osflip_monitor() {
local node_port_ids
local port
local buffer
local crm_node

node_port_ids=$(${HA_SBIN_DIR}/attrd_updater --query -n openstack_ports -N $HOSTNAME \
crm_node=$(crm_node -n)
node_port_ids=$(${HA_SBIN_DIR}/attrd_updater --query -n openstack_ports -N $crm_node \
| awk -F= '{gsub("\"","");print $NF}' \
| tr ',' ' ' \
| awk -F: '{print $NF}')
Expand All @@ -162,13 +164,13 @@ osflip_monitor() {
for port in $node_port_ids ; do
if echo $result | grep -q $port ; then
floating_ip=$(echo $result | awk '/floating_ip_address/ {print $2}')
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_floating_ip -v $floating_ip
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -S status -n openstack_floating_ip -v $floating_ip

return $OCF_SUCCESS
fi
done

${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -D -n openstack_floating_ip
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -D -S state -n openstack_floating_ip
ocf_log warn "$OCF_RESKEY_ip_id is not attached to any fixed address"
return $OCF_NOT_RUNNING
}
Expand Down Expand Up @@ -207,9 +209,13 @@ osflip_start() {
fi

# Get port_id from subnet_id
node_port_ids=$(${HA_SBIN_DIR}/attrd_updater --query -n openstack_ports -N $HOSTNAME \
node_port_ids=$(${HA_SBIN_DIR}/attrd_updater --query -n openstack_ports -N $(crm_node -n) \
| awk '{gsub("value=","") ; gsub("\"","") ; print $NF}')
node_port_id=$(echo $node_port_ids|tr ',' '\n'|awk -F: "/$OCF_RESKEY_subnet_id/ {print \$2}")

node_port_id=$(echo $node_port_ids \
| tr ',' '\n' \
| awk -F: "/$OCF_RESKEY_subnet_id/ {print \$2}")

ocf_log info "Moving IP address $OCF_RESKEY_ip_id to port ID $node_port_id"

$OCF_RESKEY_openstackcli floating ip set --port $node_port_id $OCF_RESKEY_ip_id
Expand Down
26 changes: 22 additions & 4 deletions heartbeat/openstack-info
Expand Up @@ -115,6 +115,10 @@ OSInfoStats() {
--format value --column ID --column Name \
| grep $node)

if [ $? -ne 0 ] ; then
ocf_exit_reason "cannot find $node in instances list"
exit $OCF_ERR_GENERIC
fi
node_id=$(echo $result|awk '{print $1}')

# Nova data: flavor, AZ…
Expand Down Expand Up @@ -148,14 +152,26 @@ OSInfoStats() {
value="$value,$p"
fi
done
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_ports -v $value
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_ports -v "$value"

if [ ! -z "$OS_REGION_NAME" ] ; then
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_region -v $OS_REGION_NAME
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_region -v "$OS_REGION_NAME"
fi

if [ ! -z "$OS_TENANT_ID" ] ; then
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_tenant_id -v "$OS_TENANT_ID"

if [ ! -z "$OS_TENANT_NAME" ] ; then
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_tenant_name -v "$OS_TENANT_NAME"
fi
else
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_project_id -v "$OS_PROJECT_ID"

if [ ! -z "$OS_PROJECT_NAME" ] ; then
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_project_name -v "$OS_PROJECT_NAME"
fi
fi

${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_tenant_name -v $OS_TENANT_NAME
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -n openstack_tenant_id -v $OS_TENANT_ID
}

OSInfo_usage() {
Expand All @@ -181,6 +197,8 @@ OSInfo_stop() {
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -D -n openstack_region
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -D -n openstack_tenant_id
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -D -n openstack_tenant_name
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -D -n openstack_project_id
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -D -n openstack_project_name
exit $OCF_SUCCESS
}

Expand Down