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

Reverse-spec · Clients

python-designateclient — Interactions

Interactions — python-designateclient — branch stable/2026.2

Branch stable/2026.2 @ 9231eef90192 — repository https://opendev.org/openstack/python-designateclient — analysed on 2026-11-01

[observed] means seen on the local stub. The stub shows what the client sends, not what a service accepts.

Keystone

OSC authenticates, not the plugin. The plugin takes instance.session (designateclient/osc/plugin.py:39). The token comes once per process, when the first request needs it [observed: tokens_requested is 1 in the scenarios]. On a 401, keystoneauth invalidates the token, fetches a new one and retries once (keystoneauth1:keystoneauth1/session.py:1130) [observed: 401]. The quota commands also read the project of the token: client.session.get_project_id() (designateclient/v2/cli/quotas.py:56).

Endpoint discovery

The adapter is built with service_type='dns', interface, region_name and version='2' (designateclient/v2/client.py:131). keystoneauth therefore looks up the dns catalog entry, then reads the version document.

SituationResult [observed]Scenario
catalog /dns; root answers the list of Designate (v2, v2.0 to v2.4, all linking to /dns/v2)requests go to /dns/v2/...discovery-real-shape
root lists only v2samediscovery-only-v2
root uses the Keystone wrapper {"versions": {"values": [...]}}samediscovery-values-wrapper
root answers 404warning Failed to contact the endpoint ... Fallback to using that endpoint as the base url.; requests go to /dns/zones, **without /v2**discovery-root-404
root lists only v3Could not find requested endpoint in Service Catalog., exit 1discovery-only-v3
catalog /dns/v2no discovery request; requests go to /dns/v2/..., even if the root answers 404discovery-catalog-v2-url, discovery-catalog-v2-url-root-404
no dns entrypublic endpoint for dns service in RegionOne region not found, exit 1no-dns-in-catalog

The warning is in keystoneauth1:keystoneauth1/discover.py:1500. The real document was read in designate:designate/api/versions.py:37.

Designate: request format

ElementValueSource
Transportkeystoneauth LegacyJsonAdapter, raise_exc=False, no retry added by the clientdesignateclient/v2/client.py:40, designateclient/v2/client.py:58
Acceptapplication/json, except text/dns on zone export showfilekeystoneauth1:keystoneauth1/adapter.py:671, designateclient/v2/zones.py:175
Content-Typeapplication/json on every request, GET and DELETE included, except text/dns on a plain importdesignateclient/v2/client.py:89, designateclient/v2/zones.py:188
User-Agentpython-designateclient-7.0.1 in this run [observed]designateclient/v2/client.py:137
X-Auth-Tokenthe token, through keystoneauth [observed]
Bodyjsonutils.dumps, unless the content type is text/dnsdesignateclient/client.py:46
Query stringurlencode of the criterion; * goes as %2A [observed: pagination-two-pages]designateclient/client.py:32

build_url always appends ?, even with no parameter (designateclient/client.py:41). It does not reach the wire: the stub logs /dns/v2/zones [observed].

Optional headers

HeaderValueSet byRead in Designate at
X-Auth-All-ProjectsTrue--all-projects, or implicitly by quota commandsdesignate:designate/api/middleware.py:65
X-Auth-Sudo-Project-IDproject ID--sudo-project-iddesignate:designate/api/middleware.py:57
X-Designate-Edit-Managed-RecordsTrue--edit-manageddesignate:designate/api/middleware.py:87
X-Designate-Hard-DeleteTrue--hard-deletedesignate:designate/api/middleware.py:95
X-Designate-Delete-Sharestrue--delete-sharesdesignate:designate/api/middleware.py:108

Python str(True) gives the capital.

Routes

The full list is in [api-surface_stable-2026.2.md](_rewrite/api-surface_stable-2026.2.md), per command in 01 § 5.

FamilyBase routeVerbsNotes
Zones/zones, /zones/{id}GET, POST, PATCH, DELETE
Zone tasks/zones/{id}/tasks/abandon, xfr, pool_move, export, transfer_requestsPOST
Name servers/zones/{id}/nameserversGET
Shares/zones/{id}/shares, /zones/{id}/shares/{id}GET, POST, DELETE
Recordsets/zones/{id}/recordsets, /recordsetsGET, POST, PUT, DELETE
Transfers/zones/tasks/transfer_requests, /zones/tasks/transfer_acceptsGET, POST, PATCH, DELETE
Exports/zones/tasks/exports, .../{id}/exportGET, DELETE
Imports/zones/tasks/importsGET, POST, DELETE
Floating IPs/reverse/floatingips, /reverse/floatingips/{region}:{id}GET, PATCH
Administration/blacklists, /tlds, /tsigkeys, /quotas/{project}, /limits, /service_statusesvarious

Filters per list command

Read in Designate, a filter outside the accepted list raises 400 Invalid filters (designate:designate/api/v2/controllers/rest.py:73).

CommandFilters sentAccepted by Designate, by reading
zone listtype, name, ttl, description, email, statusall (designate:designate/api/v2/controllers/zones/__init__.py:70)
recordset listtype, name, data, ttl, description, status, **action**all except action (designate:designate/api/v2/controllers/common.py:25)
tld listnameyes (designate:designate/api/v2/controllers/tlds.py:54)
tsigkey listname, algorithm, scopeyes (designate:designate/api/v2/controllers/tsigkeys.py:55)
zone blacklist listpatternyes (designate:designate/api/v2/controllers/blacklists.py:56)
dns service listhostname, service_name, statusyes (designate:designate/api/v2/controllers/service_status.py:34)
zone export liststatus, zone_idyes (designate:designate/api/v2/controllers/zones/tasks/exports.py:102)
zone import liststatus, zone_id, messageyes (designate:designate/api/v2/controllers/zones/tasks/imports.py:58)
zone transfer request liststatusyes (designate:designate/api/v2/controllers/zones/tasks/transfer_requests.py:60)
zone transfer accept liststatusyes (designate:designate/api/v2/controllers/zones/tasks/transfer_accepts.py:59)
zone share listtarget_project_idyes (designate:designate/api/v2/controllers/zones/sharedzones.py:58)

Sample exchanges [observed, stub answers]

$ openstack recordset create 11111111-2222-4333-8444-555555555555 www --type A --record 192.0.2.1 --record 192.0.2.2 --ttl 60 --description d
GET /dns/v2/zones/11111111-2222-4333-8444-555555555555
POST /dns/v2/zones/11111111-2222-4333-8444-555555555555/recordsets
Content-Type: application/json
{"name": "www.example.org.", "type": "A", "records": ["192.0.2.1", "192.0.2.2"], "ttl": 60, "description": "d"}
$ openstack zone import create zone.file --attributes k:v
POST /dns/v2/zones/tasks/imports
Content-Type: application/json
{"zonefile": "$ORIGIN example.org.\n", "attributes": {"k": "v"}}

Local files

zone import create opens the given path in text mode with the default encoding (designateclient/v2/cli/zones.py:736). Nothing else touches the disk. No command runs a binary or reads a terminal; grep on subprocess, getpass and input( outside tests finds nothing.

Python API users

Read in the local clones, not run. They rely on the exception classes and the name resolution of the controllers.

UserCallsRelies onSource
Neutron external DNS driverClient(session=, auth=), endpoint_override=, edit_managed=True, all_projects=True; recordsets.create, recordsets.delete, recordsets.list, zones.createNotFound, Conflict, OverQuota, BadRequest, Forbidden; a zone given by nameneutron:neutron/services/externaldns/drivers/designate/driver.py:46, neutron:neutron/services/externaldns/drivers/designate/driver.py:104, neutron:neutron/services/externaldns/drivers/designate/driver.py:177
Heatclient.Client(version='2', session=, endpoint_type=, service_type=, region_name=); zones.*, recordsets.*NotFound (is_not_found)heat:heat/engine/clients/os/designate.py:32, heat:heat/engine/resources/openstack/designate/zone.py:160, heat:heat/engine/resources/openstack/designate/recordset.py:105

Neutron's edit_managed=True is set at construction, so Client keeps it for all calls; only the commands reset these values.

Not used

Database, AMQP, Redis, gRPC, subprocess: none. In the inventory, the db occurrences are false positives on client.session.delete (designateclient/client.py:84), the config occurrences are the options of the functional tests (designateclient/functionaltests/config.py:21), and the async occurrence is the pagination loop.

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