OpenKeel: the sovereign French Cloud solution of the inherent group, with a European reach Discover inherent

Reverse-spec · Clients

python-designateclient — Summary

Reverse-specification of python-designateclient — branch stable/2026.2

Branch stable/2026.2 @ 9231eef90192 (7.0.0 + 2 maintenance commits; package version 7.0.1.dev2) — repository https://opendev.org/openstack/python-designateclient — analysed on 2026-11-01

  • Scope: the whole repository: OSC plugin, Python API, tests and the unused functional tests. The change history (step 7) was not requested, so there is no file 06.
  • Dependencies read at fixed versions, from the shared venv: osc-lib 4.7.0, cliff 4.16.0, python-openstackclient 10.3.1, keystoneauth1 5.17.0, openstacksdk 4.20.0. They are cited with the prefixes osc-lib:, cliff:, openstackclient:, keystoneauth1: and openstacksdk:.
  • Also read, never started: designate stable/2026.2 @ e3dd774db145, neutron stable/2026.2 @ eef1a0f7ee36, heat stable/2026.2 @ 5872396e548c, with the prefixes designate:, neutron: and heat:.
  • References are file:line from the repository root. [observed] means seen by running the real openstack shell against a local stub on 127.0.0.1. [inferred] means not followed to the end.
  • Observed behaviour against a stub says nothing about a real service. The stub answers what it is told to. No Designate, Keystone, lab or cloud was contacted.

Files of this specification

FileContent
01-cli-commands_stable-2026.2.mdshared mechanics, functional description by family, Python API, and the 60 commands with their arguments, requests and what they read in the response
02-errors_stable-2026.2.mdexit codes, exception classes, status translation, client-side errors, 18 defects
03-interactions_stable-2026.2.mdKeystone, discovery, Designate requests and headers, local file, Python API users
04-scenarios_stable-2026.2.md5 scenarios with sequence diagrams and diagnostics
05-async-processing_stable-2026.2.mdno background processing; the only loop is pagination
07-rewrite-pack_stable-2026.2.mdclient contract: what the client requires from a DNS service, test vectors, proof and limits
_verification_stable-2026.2.mdoutput of the reference checker

Overview

The package has two layers. designateclient.v2.client.Client is a Python library with one controller per resource, on top of a keystoneauth adapter that translates HTTP statuses into exceptions. designateclient.v2.cli holds 60 command classes for openstack, loaded from entry points. Each invocation is one short-lived openstack process that authenticates, discovers the DNS endpoint, sends one to three requests, prints a table and exits. There is no database, bus, cache, server or daemon, and **no separate designate shell** on this branch.

Architecture

flowchart LR
  user[User or script] -->|argv, env, zone file| osc[openstack process]
  osc -->|entry points| cli[designateclient.v2.cli]
  cli --> client[designateclient.v2.client.Client]
  neutron[neutron external DNS driver] -->|Python API| client
  heat[heat designate resources] -->|Python API| client
  client --> adapter[DesignateAdapter on keystoneauth1]
  adapter -->|HTTPS, token| ks[Keystone]
  adapter -->|HTTPS REST /v2, X-Auth-Token| dns[Designate API]

Processes

ProcessEntry pointRoleListens to / consumes
openstack (python-openstackclient)pyproject.toml:39 → designateclient/osc/plugin.py:33runs one commandargv, environment, one local file for zone import create; listens on nothing

No legacy shell: pyproject.toml declares no script. designateclient/functionaltests/client.py:372 wraps the openstack binary for tests that need a live cloud.

External dependencies

SystemProtocolLibraryConfigurationUsage
KeystoneHTTPS RESTkeystoneauth1, through OSC--os-auth-url, clouds.yaml, OS_*token, catalog, project ID
Designate APIHTTPS RESTkeystoneauth1 LegacyJsonAdaptercatalog entry of type dnsevery command
osprofilerHTTP headersoptional, imported if presentnonetrace headers (designateclient/v2/client.py:92); not exercised

Key figures

ItemCount
Commands60 in openstack.dns.v2, 265 arguments: 14 lists, 34 single objects, 12 with no output
Controllers in the Python API15; 2 are used by no command (pools, nameservers)
Operations used on Designate61 method and route pairs, 59 seen in the probes, 2 more in the defect scenarios; all 61 exist in the Designate routes (static comparison)
Commands that reached a real route on the stub60 of 60 in all three modes
Requests recorded60 in 404 mode, 60 in {} mode, 61 in fixture mode; exit 0 for 60 of 60 in fixture mode
Defect scenarios on the stub103
Exception classes11, in designateclient/exceptions.py
Unit tests111 of 111 pass, twice, giving 97 vectors (87 API, 10 command); 5 of 60 command classes have a command vector

Points of attention

Details and sources are in 02 § 4.

  1. Untranslated 4xx is success [observed]: 405, 406, 415, 429 and any other unlisted 4xx exit 0. A Command prints nothing, and a ShowOne prints the fault as if it were the resource (designateclient/v2/client.py:107). Scripts cannot detect the failure.
  2. **ptr record set --no-description and --no-ttl do nothing [observed]**, and exit 0 (designateclient/v2/cli/reverse.py:114).
  3. **--ttl 0 is dropped by zone set and recordset set [observed]**, while zone create and ptr record set send it (designateclient/v2/cli/zones.py:234).
  4. Implicit all-projects on quotas [observed]: dns quota set and reset without --project-id send X-Auth-All-Projects: True (designateclient/v2/cli/quotas.py:102). A token with no project gives PATCH /quotas/None.
  5. **Sticky headers in one process [observed through run_subcommand]**: --sudo-project-id and --hard-delete carry over to later commands in the interactive shell (designateclient/v2/cli/common.py:86). This matters for a destructive flag. One-shot runs are not affected.
  6. **recordset list --action sends a filter that Designate refuses** [request observed; refusal read in Designate, not run].
  7. Pagination has no limit [observed]: a repeated or null links.next loops forever (designateclient/v2/utils.py:70).
  8. Discovery matters [observed]: a catalog URL without /v2 whose root answers 404 makes the client send /dns/zones, without the version. A rewrite must serve the version document, or register the URL with /v2.
  9. Response keys are hard requirements [observed]: a missing key gives a bare 'zones' or 'masters', exit 1; an empty object on a ShowOne gives an unpacking error; an empty 202 on a delete gives a crash after the change was accepted.
  10. Unit tests catch none of this: the 10 command tests mock the client, and the 87 API tests use requests-mock with friendly bodies.

Not found: the OSC defect of a command.Command returning a value. None of the 12 classes does (02 § 1).

Blind spots / [inferred]

  • No real Designate was contacted. Every statement about what a service accepts is either read in the Designate clone, and marked so, or unknown. Function and field checks in reverse-spec-designate were not re-verified.
  • Fixture mode bodies are hand-written from the Designate adapters. They prove the formatters work on these bodies, not on real ones.
  • The functional tests (designateclient/functionaltests/) need a cloud and a Tempest configuration (designateclient/functionaltests/config.py:21), so they were not run.
  • The interactive shell was not run, because it reads a terminal. Defect 8 calls run_subcommand, the same method the loop calls.
  • osprofiler is installed in the venv, but no trace was enabled, so its headers (designateclient/v2/client.py:92) were not exercised.
  • **Connection failures and --timeout** were not reproduced.
  • **TLS, clouds.yaml and non-password auth** are OSC and keystoneauth matters, not analysed here; the probes used password auth only.
  • Output formatters (-f json, -c, and so on) come from cliff and were not specified per command.
  • **doc/** was not compared with the code in detail.
  • In-process runs: the probes reset the client cache between commands to mimic separate processes, but they share a Python process. Global state outside that cache was not isolated.

Source: reverse-spec-python-designateclient/00-summary_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.