apiVersion: v1 data: swift-ring-tool: | #!/usr/bin/env bash TARFILE="/tmp/swiftrings.tar.gz" BASE_URL="https://kubernetes.default.svc/api/v1/namespaces/${NAMESPACE}/configmaps" URL="${BASE_URL}/${CM_NAME}" DEVICESFILE="/var/lib/config-data/ring-devices/devices.txt" # Credentials to be used by curl export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) function get() { # Get the ConfigMap with the Swiftrings if it exists. If it exists, untar it # and update the rings. If it does not exist, create a new ConfigMap using a # POST request. If the response code is neither 200 or 404 fail early, b/c it # is unclear if there might be an existing set of rings that should not be # overwritten HTTP_CODE=$(/usr/bin/curl \ -H "Authorization: Bearer $TOKEN" \ -o "${CM_NAME}.json" \ -w "%{http_code}" \ --silent --show-error --fail-with-body \ -X GET "${URL}") case $HTTP_CODE in "200") # Configmap was found # Get JSON keyvalue without jq grep -e '"swiftrings.tar.gz": ".*"' "${CM_NAME}.json" | cut -f 4 -d '"' | base64 -d > $TARFILE [ -s $TARFILE ] && tar --totals -xzf $TARFILE grep -e '"account.ring.gz": ".*"' "${CM_NAME}.json" | cut -f 4 -d '"' | base64 -d > account.ring.gz grep -e '"container.ring.gz": ".*"' "${CM_NAME}.json" | cut -f 4 -d '"' | base64 -d > container.ring.gz grep -e '"object.ring.gz": ".*"' "${CM_NAME}.json" | cut -f 4 -d '"' | base64 -d > object.ring.gz ;; "404") rm "${CM_NAME}.json" ;; *) cat "${CM_NAME}.json" rm "${CM_NAME}.json" exit 1 ;; esac } function init() { # Create new rings if not existing for f in account container object; do [ ! -e ${f}.builder ] && [ -s ${f}.ring.gz ] && { echo "${f}.ring.gz file found without ${f}.builder - exiting" ; exit 0; } [ ! -e ${f}.builder ] && swift-ring-builder ${f}.builder create ${SWIFT_PART_POWER} ${SWIFT_REPLICAS} ${SWIFT_MIN_PART_HOURS} || true done } function update() { # Iterate over all devices from the list created by the SwiftStorage CR. while read REGION ZONE HOST DEVICE_NAME WEIGHT NODE; do # Check if host/disk exists and only add if not swift-ring-builder account.builder search --ip $HOST --device $DEVICE_NAME [ $? -eq 2 ] && swift-ring-builder account.builder add --region $REGION --zone $ZONE --ip $HOST --port 6202 --device $DEVICE_NAME --weight $WEIGHT --meta "$NODE" # Check if host/disk exists and only add if not swift-ring-builder container.builder search --ip $HOST --device $DEVICE_NAME [ $? -eq 2 ] && swift-ring-builder container.builder add --region $REGION --zone $ZONE --ip $HOST --port 6201 --device $DEVICE_NAME --weight $WEIGHT --meta "$NODE" # Check if host/disk exists and only add if not swift-ring-builder object.builder search --ip $HOST --device $DEVICE_NAME [ $? -eq 2 ] && swift-ring-builder object.builder add --region $REGION --zone $ZONE --ip $HOST --port 6200 --device $DEVICE_NAME --weight $WEIGHT --meta "$NODE" done < $DEVICESFILE } function metaswap() { /usr/bin/env python3 << EOF from swift.common.ring import RingBuilder builder = RingBuilder.load("$1") for dev in builder.devs: if dev.get('meta') and dev.get('device') == 'pv': dev['meta'], dev['ip'] = dev['ip'], dev['meta'] builder.save("$1") EOF } function rebalance() { for f in *.builder; do metaswap $f || exit swift-ring-builder $f rebalance metaswap $f || exit swift-ring-builder $f write_ring done } function forced_rebalance() { for f in *.builder; do swift-ring-builder $f pretend_min_part_hours_passed done rebalance } function drain() { for f in *.builder; do swift-ring-builder $f set_weight --ip $1 0 --yes done } function remove() { for f in *.builder; do swift-ring-builder $f remove $1 done } function push() { # Tar up all the ring data and either create or update the SwiftRing ConfigMap BINARY_DATA=`tar --totals -cz *.builder *.ring.gz backups/*.builder | /usr/bin/base64 -w 0` ACCOUNT_RING_GZ=`base64 -w 0 account.ring.gz` CONTAINER_RING_GZ=`base64 -w 0 container.ring.gz` OBJECT_RING_GZ=`base64 -w 0 object.ring.gz` if [ ! -e "${CM_NAME}.json" ]; then METHOD="POST" URL="${BASE_URL}" VERSION="" else METHOD="PUT" VERSION="$(grep -oP '"resourceVersion": ".*"' "${CM_NAME}.json")," fi CONFIGMAP_JSON='{ "apiVersion":"v1", "kind":"ConfigMap", "metadata":{ '${VERSION}' "name":"'${CM_NAME}'", "namespace":"'${NAMESPACE}'", "finalizers": ["openstack.org/swiftring"], "ownerReferences": [ { "apiVersion": "'${OWNER_APIVERSION}'", "kind": "'${OWNER_KIND}'", "name": "'${OWNER_NAME}'", "uid": "'${OWNER_UID}'" } ] }, "binaryData":{ "swiftrings.tar.gz": "'${BINARY_DATA}'", "account.ring.gz": "'${ACCOUNT_RING_GZ}'", "container.ring.gz": "'${CONTAINER_RING_GZ}'", "object.ring.gz": "'${OBJECT_RING_GZ}'" } }' # https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/config-map-v1/#update-replace-the-specified-configmap RESPONSE_BODY=$(/usr/bin/curl \ -H "Authorization: Bearer $TOKEN" \ --data-binary "${CONFIGMAP_JSON}" \ -H 'Content-Type: application/json' \ --silent --show-error --fail-with-body \ -X "${METHOD}" "${URL}") [ $? -ne 0 ] && echo -e "${RESPONSE_BODY}" || true } function usage() { echo "Usage: $0 [get|init|update|rebalance|push|all]" echo echo "get Fetch rings from ConfigMap ${CM_NAME}" echo "init Create new .builder files if not existing" echo "update Update rings using input from ${DEVICESFILE}" echo "rebalance Rebalance rings" echo "push Push rings to ConfigMap ${CM_NAME}" echo "all All above operations in sequence" echo echo "drain Set weight of all node devices to 0" echo "remove Remove node from all rings" echo } case $1 in "all") get init update rebalance push ;; "get") get ;; "init") init ;; "update") update ;; "drain") drain $2 ;; "remove") remove $2 ;; "metaswap") metaswap $2 ;; "rebalance") rebalance ;; "forced_rebalance") forced_rebalance ;; "push") push ;; *) usage exit 1 ;; esac kind: ConfigMap metadata: creationTimestamp: "2025-10-11T10:53:44Z" labels: job-name: swift-ring-rebalance name: swift-ring-scripts namespace: openstack ownerReferences: - apiVersion: swift.openstack.org/v1beta1 blockOwnerDeletion: true controller: true kind: SwiftRing name: swift-ring uid: 73ef0cb7-0be8-433b-a18d-80240c2f129d resourceVersion: "37258" uid: e9c7336c-fabe-46ef-9123-50f8e2668700