Skip to content

Deploy Qonos

QonoS v2 is a modern, extensible scheduling platform for executing time-based actions against OpenStack services. It provides cron-scheduled operations including server snapshots (Nova), volume full and incremental backups (Cinder), with Keystone authentication, trust-based delegation, retention policies, and RabbitMQ notifications.

Genestack deploys QonoS with three control-plane components — API, scheduler, and worker — backed by MariaDB and RabbitMQ.

This document outlines deploying QonoS using Genestack.

Supported action types

Action type Description
server_snapshot Create a Glance image snapshot of a Nova server
volume_backup_full Full Cinder backup of a block storage volume
volume_backup_incremental Incremental Cinder backup

Each schedule references an execution profile with Keystone trust delegation so tenant-scoped jobs run under the correct OpenStack project context.

Note

QonoS can be enabled during bin/setup-openstack.sh (component prompt Qonos (Scheduled Actions)) or installed later with /opt/genestack/bin/install-qonos.sh.

Create secrets

Information about the secrets used

Manual secret generation is only required if you haven't run the create-secrets.sh script located in /opt/genestack/bin.

Example secret generation
kubectl --namespace openstack \
        create secret generic qonos-rabbitmq-password \
        --type Opaque \
        --from-literal=username="qonos" \
        --from-literal=password="$(< /dev/urandom tr -dc _A-Za-z0-9 | head -c${1:-64};echo;)"
kubectl --namespace openstack \
        create secret generic qonos-db-password \
        --type Opaque \
        --from-literal=password="$(< /dev/urandom tr -dc _A-Za-z0-9 | head -c${1:-32};echo;)"
kubectl --namespace openstack \
        create secret generic qonos-admin \
        --type Opaque \
        --from-literal=password="$(< /dev/urandom tr -dc _A-Za-z0-9 | head -c${1:-32};echo;)"

Configure Qonos

The install script renders qonos.conf into the qonos-etc secret. It prefers a site override, then falls back to the shipped default:

Source Path
Override /etc/genestack/kustomize/qonos/base/qonos.conf
Default /opt/genestack/base-kustomize/qonos/base/qonos.conf

Tip

Copy the default template to /etc/genestack/kustomize/qonos/base/qonos.conf before install if you need region-specific timeouts, concurrency, or endpoints.

Run the package deployment

Run the Qonos deployment Script /opt/genestack/bin/install-qonos.sh

#!/usr/bin/env bash
set -euo pipefail

SERVICE_NAME="qonos"
SERVICE_NAMESPACE="openstack"

GENESTACK_BASE_DIR="${GENESTACK_BASE_DIR:-/opt/genestack}"
GENESTACK_OVERRIDES_DIR="${GENESTACK_OVERRIDES_DIR:-/etc/genestack}"
KUSTOMIZE_PATH="${GENESTACK_BASE_DIR}/base-kustomize/${SERVICE_NAME}/base"
QONOS_CONF_DEFAULT="${KUSTOMIZE_PATH}/qonos.conf"
QONOS_CONF_OVERRIDE="${GENESTACK_OVERRIDES_DIR}/kustomize/qonos/base/qonos.conf"

resolve_qonos_conf() {
    if [ -f "${QONOS_CONF_OVERRIDE}" ]; then
        echo "${QONOS_CONF_OVERRIDE}"
        return 0
    fi

    if [ -f "${QONOS_CONF_DEFAULT}" ]; then
        echo "${QONOS_CONF_DEFAULT}"
        return 0
    fi

    echo "Error: qonos.conf not found. Looked for:" >&2
    echo "  ${QONOS_CONF_OVERRIDE}" >&2
    echo "  ${QONOS_CONF_DEFAULT}" >&2
    exit 1
}

require_secret() {
    local secret_name="$1"

    if ! kubectl --namespace "${SERVICE_NAMESPACE}" get secret "${secret_name}" >/dev/null 2>&1; then
        echo "Error: secret ${secret_name} not found in namespace ${SERVICE_NAMESPACE}" >&2
        echo "Run bin/create-secrets.sh and apply /etc/genestack/kubesecrets.yaml first." >&2
        exit 1
    fi
}

get_secret_password() {
    local secret_name="$1"

    kubectl --namespace "${SERVICE_NAMESPACE}" get secret "${secret_name}" \
        -o jsonpath='{.data.password}' | base64 -d
}

apply_qonos_etc_secret() {
    local conf_template="$1"
    local rendered_conf
    local qonos_db_password
    local qonos_rabbitmq_password
    local qonos_admin_password

    qonos_db_password="$(get_secret_password qonos-db-password)"
    qonos_rabbitmq_password="$(get_secret_password qonos-rabbitmq-password)"
    qonos_admin_password="$(get_secret_password qonos-admin)"

    rendered_conf="$(mktemp)"
    trap 'rm -f "${rendered_conf}"' RETURN

    sed \
        -e "s|__QONOS_DB_PASSWORD__|${qonos_db_password}|g" \
        -e "s|__QONOS_RABBITMQ_PASSWORD__|${qonos_rabbitmq_password}|g" \
        -e "s|__QONOS_ADMIN_PASSWORD__|${qonos_admin_password}|g" \
        "${conf_template}" > "${rendered_conf}"

    kubectl create secret generic qonos-etc \
        --namespace "${SERVICE_NAMESPACE}" \
        --from-file=qonos.conf="${rendered_conf}" \
        --dry-run=client -o yaml | kubectl apply -f -
}

if [ ! -f "${KUSTOMIZE_PATH}/kustomization.yaml" ]; then
    echo "Error: qonos kustomization not found at ${KUSTOMIZE_PATH}" >&2
    exit 1
fi

QONOS_CONF_PATH="$(resolve_qonos_conf)"

echo "Installing qonos from ${KUSTOMIZE_PATH}"
echo "Rendering qonos.conf from ${QONOS_CONF_PATH}"

require_secret "keystone-keystone-admin"
require_secret "qonos-db-password"
require_secret "qonos-rabbitmq-password"
require_secret "qonos-admin"

apply_qonos_etc_secret "${QONOS_CONF_PATH}"

kubectl --namespace "${SERVICE_NAMESPACE}" delete job qonos-ks-user qonos-db-sync --ignore-not-found=true

kubectl kustomize "${KUSTOMIZE_PATH}" | kubectl apply -f -

kubectl --namespace "${SERVICE_NAMESPACE}" wait \
    --for=condition=complete "job/qonos-ks-user" \
    --timeout=15m

kubectl --namespace "${SERVICE_NAMESPACE}" wait \
    --for=condition=complete "job/qonos-db-sync" \
    --timeout=15m

for deployment in qonos-api qonos-scheduler qonos-worker; do
    kubectl --namespace "${SERVICE_NAMESPACE}" rollout status "deployment/${deployment}" --timeout=15m
done

echo "qonos installed successfully"

Enable Skyline integration

The Skyline Scheduled Actions tab (QonoS) is hidden until Skyline is configured with the QonoS endpoint and service user id.

Add the following to /etc/genestack/helm-configs/skyline/skyline-helm-overrides.yaml:

conf:
  skyline:
    openstack:
      qonos_endpoint: https://qonos.your.domain.tld/
      qonos_user_id: <qonos-keystone-user-id>

Resolve the user id after QonoS is deployed:

kubectl --namespace openstack exec -ti openstack-admin-client -- \
  openstack user show qonos --domain service -f value -c id

Set qonos_endpoint to the same public hostname used on the QonoS Gateway HTTPRoute, then re-run /opt/genestack/bin/install-skyline.sh so the override is applied.

Note

Without qonos_endpoint and qonos_user_id, the Scheduled Actions tab does not appear in Skyline.

Monitoring

Component Port Path
API 8080 /metrics
Worker 8081 /metrics
Scheduler 8082 /metrics

Import etc/grafana-dashboards/qonos_v2_operations.json with the Grafana dashboard import script.

Validate functionality

kubectl --namespace openstack get pods -l app.kubernetes.io/name=qonos
kubectl --namespace openstack get jobs qonos-ks-user qonos-db-sync
kubectl --namespace openstack get servicemonitor -l app.kubernetes.io/name=qonos
kubectl --namespace openstack exec -ti openstack-admin-client -- \
  openstack user show qonos --domain service