Skip to content

feat(devstack): Add devstack plugin and CI workflow#1052

Draft
gtema wants to merge 10 commits into
mainfrom
claude/rust-keystone-devstack-workflow-9y3pdm
Draft

feat(devstack): Add devstack plugin and CI workflow#1052
gtema wants to merge 10 commits into
mainfrom
claude/rust-keystone-devstack-workflow-9y3pdm

Conversation

@gtema

@gtema gtema commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add a standard out-of-tree devstack plugin (devstack/settings,
devstack/plugin.sh, devstack/lib/keystone-rs) that builds/runs the
rust Keystone binary alongside python Keystone and reroutes the
Apache /identity proxy to it, automating the manual steps already
documented in doc/src/install.md instead of reimplementing devstack.

Add .github/workflows/devstack.yml, which builds the rust binaries
and runs a minimal devstack (mysql, rabbitmq, keystone) with the
plugin enabled, verifying the Apache-fronted /identity endpoint is
served by rust Keystone.

gtema and others added 10 commits July 17, 2026 18:58
Add a standard out-of-tree devstack plugin (devstack/settings,
devstack/plugin.sh, devstack/lib/keystone-rs) that builds/runs the
rust Keystone binary alongside python Keystone and reroutes the
Apache /identity proxy to it, automating the manual steps already
documented in doc/src/install.md instead of reimplementing devstack.

Add .github/workflows/devstack.yml, which builds the rust binaries
and runs a minimal devstack (mysql, rabbitmq, keystone) with the
plugin enabled, verifying the Apache-fronted /identity endpoint is
served by rust Keystone.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
devstack's fetch_plugins defaults to fetching branch "master" when
enable_plugin is called without an explicit branch argument. The
file:// clone source used in CI only has the actual working branch
checked out, not "master", so stack.sh failed immediately with
"fatal: couldn't find remote ref master" before the plugin's own
code ever ran.

Pass the checked-out ref explicitly via GitHub Actions' ref context
so this works for both pull_request (head ref) and
workflow_dispatch/merge_group (ref name) triggers.

Signed-off-by: Claude <noreply@anthropic.com>
actions/checkout leaves the workspace in detached HEAD, so passing
the branch name to enable_plugin key-rs file://... was not enough:
devstack's fetch_plugins still failed with "git fetch origin
<branch>" because no refs/heads/<branch> existed in the checkout to
fetch from.

Create that local branch ref pointing at HEAD right after checkout
so the file:// plugin clone can find it.

Signed-off-by: Claude <noreply@anthropic.com>
ubuntu-24.04 GitHub runners ship with a system MySQL service already
running, authenticating root via auth_socket with no password set.
devstack's `enable_service mysql` then tries to configure/start its
own instance against that pre-existing one and fails:

  ERROR 1045 (28000): Access denied for user 'root'@'localhost'

Purge the pre-installed MySQL (service, packages, data dir) before
cloning/running devstack so its own install_database step sets one
up from scratch with DATABASE_PASSWORD as expected.

Signed-off-by: Claude <noreply@anthropic.com>
configure_keystone_rs created the config file with `sudo touch`,
leaving it root-owned. iniset writes directly as the unprivileged
stack user (no sudo of its own), so every iniset call against it
failed:

  tee: /etc/keystone/keystone-rs.conf: Permission denied

Create the file with `sudo install -o $STACK_USER` instead, matching
how devstack's own configure_keystone sets up $KEYSTONE_CONF_DIR.

Signed-off-by: Claude <noreply@anthropic.com>
apache_site_config_for keystone assumed a site literally named
"keystone", but devstack's write_uwsgi_config actually names it
after the uwsgi app ("keystone-api" as of current master; older
code paths reference "keystone-wsgi-public"), so the guessed name
never matched and _keystone_rs_reroute_apache always died with
"Could not find the Apache site config devstack generated for
keystone".

Locate the generated site by grepping $APACHE_CONF_DIR for whichever
file actually proxies "/identity" instead of guessing its name, so
the reroute is resilient to that naming drifting across devstack
releases.

Signed-off-by: Claude <noreply@anthropic.com>
….org

install_keystone_rs downloaded the OPA static binary from
openpolicyagent.org/downloads/..., which doesn't reliably serve a
valid binary for the pinned version - the resulting /usr/local/bin/opa
failed to run, so the OPA process never opened :8181 and
wait_for_connection's health check for it always timed out:

  die 113 "OPA did not become ready for rust Keystone"

Use the same github.com/open-policy-agent/opa/releases/download/...
URL tools/Dockerfile.skaffold already relies on instead.

Signed-off-by: Claude <noreply@anthropic.com>
devstack's run_process only calls _run_under_systemd (which writes
and starts the systemd unit) when is_service_enabled $service is
true - otherwise it silently no-ops, with no error. init_keystone_rs
calls `run_process key-rs-opa ...`, but "key-rs-opa" was never
enabled anywhere (only "key-rs" is, via devstack/settings/local.conf),
so the OPA process was never actually launched at all - explaining
why journalctl -u devstack@key-rs-opa showed no entries and the
subsequent health-check loop just timed out.

key-rs-opa is an internal sidecar, not something local.conf should
need to opt into separately, so enable it unconditionally in
plugin.sh whenever key-rs itself is enabled.

Signed-off-by: Claude <noreply@anthropic.com>
rust Keystone defaults [audit] spool_dir to /var/lib/keystone/audit,
which the unprivileged stack user devstack runs the key-rs systemd
unit as cannot create:

  0: failed to create audit spool directory
  1: Permission denied (os error 13)

Configure it to $DATA_DIR/keystone-rs/audit instead, devstack's own
per-service data directory convention, pre-created and owned by
$STACK_USER.

Signed-off-by: Claude <noreply@anthropic.com>
The keystone Apache site devstack generates targets a "uwsgi://"
backend, so only mod_proxy/mod_proxy_uwsgi get enabled for it.
_keystone_rs_reroute_apache rewrites its ProxyPass target to a plain
"http://127.0.0.1:8080" backend, which mod_proxy_http is required to
service - without it Apache can't fulfil the directive at all, so
every /identity request through the proxy failed:

  curl -sf http://127.0.0.1/identity/v3
  Process completed with exit code 22.

(systemctl is-active devstack@key-rs reported "active" - the rust
process itself was fine, only the proxy hop was broken.)

Signed-off-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants