Interactions — python-heatclient — branch stable/2026.2
Branch
stable/2026.2@88120f11830d(5.3.0-2-g88120f1) — repository https://opendev.org/openstack/python-heatclient — analysed on 2026-11-01
No database, message bus or cache: the inventory finds 0 RPC calls and 0 triggers. The client talks HTTP to Heat, Keystone and, in one path, Swift, and it reads local files and URLs. [observed] means seen on the local stub, not on a real service.
| System | Protocol | Library | Direction | Mode |
|---|---|---|---|---|
| Heat | HTTPS REST | keystoneauth1 session, adapter SessionClient (heatclient/common/http.py:303) | outbound | synchronous, one request at a time |
| Keystone | HTTPS REST | keystoneauth1, python-keystoneclient for --project | outbound | synchronous |
| Swift | HTTPS REST | python-swiftclient (heatclient/common/deployment_utils.py:134-152) | outbound | legacy shell only, see § 3 |
| Local files, URLs | file:, http(s):, any urllib scheme | urllib.request.urlopen | read; --output-file writes | synchronous |
No subprocess call exists in the package, and nothing reads a terminal except the two delete prompts (heatclient/osc/v1/stack.py:753-756, heatclient/osc/v1/snapshot.py:216-220).
1. Heat
Endpoint and session
- Discovery: Keystone catalog,
service_type=orchestration, with the region and interface of OSC (heatclient/osc/plugin.py:38-43). The URL is used as published, normally<heat>/v1/{tenant_id}. NeitherGET /nor a version document is requested [observed: 0 hits]. - Credentials: the OSC session's token. The session re-authenticates once on a 401 (
keystoneauth1:keystoneauth1/session.py:1130-1131) [observed, E09]. - Timeouts and retries: none set here; the session's values apply. No retry on 5xx or 409.
- Redirects: keystoneauth follows 301, 302, 303, 305, 307 and 308 up to its limit, re-sending the same method and body (
keystoneauth1:keystoneauth1/session.py:385,keystoneauth1:keystoneauth1/session.py:1246) [observed].
Headers [observed]
| Header | Value | Source |
|---|---|---|
X-Auth-Token | session token | keystoneauth |
Accept | application/json | keystoneauth1:keystoneauth1/adapter.py:671 |
Content-Type | application/json, on every request including GET | heatclient/common/http.py:310-311 |
User-Agent | python-heatclient | heatclient/common/http.py:34, heatclient/common/http.py:308 |
X-Region-Name | --os-region-name, when set | heatclient/common/http.py:363-365 |
Request bodies are always jsonutils.dumps of a Python value (heatclient/common/http.py:313-314).
Routes
The full list, with sources and users, is in [_rewrite/api-surface_stable-2026.2.md](_rewrite/api-surface_stable-2026.2.md) (57 operations). Each command's list is in [_rewrite/client-contract_stable-2026.2.json](_rewrite/client-contract_stable-2026.2.json).
Name resolution
| Form | Sends | Used by | Source |
|---|---|---|---|
| Direct | <METHOD> /stacks/{typed}[/resources|events|template|actions|environment|files], follows Heat's 302 | stacks.get, update, delete, template, environment, files; actions.*; resources.list; events.list | heatclient/v1/stacks.py:182-185, heatclient/v1/stacks.py:298, heatclient/v1/actions.py:39 |
| Resolved | GET /stacks/{typed} with redirect off; then /stacks/{after /stacks/ in Location}/… | everything else on a stack | heatclient/v1/stacks.py:102-116 |
Heat answers 302 on /stacks/{name} for every method, and on those sub-paths for GET (POST except environment and files), keeping the query (heat:heat/api/openstack/v1/__init__.py:155-183, heat:heat/api/openstack/v1/stacks.py:426-442). The stub copies this. **The query must survive in Location**: the client sends ?resolve_outputs=False on the first request only, and keystoneauth just follows the header [observed: the stub's fixed Location dropped it in G01].
Path values: the stack manager inserts stack_id, snapshot_id and output_key unquoted (heatclient/v1/stacks.py:248, heatclient/v1/stacks.py:281). The resource and event managers quote them (heatclient/v1/resources.py:80-82, heatclient/v1/events.py:82-85).
Query parameters [observed]
Values that are falsy are dropped by the managers (heatclient/v1/stacks.py:153-155), except for the two with_* flags, always sent.
| Command | Option | Parameter |
|---|---|---|
stack list | --property k=v | k=v, directly in the query |
--limit, --marker | limit, marker | |
--tags t | tags=t | |
--tags t --tag-mode any / not / not-any | tags_any, not_tags, not_tags_any (heatclient/osc/v1/stack.py:678-690) | |
--all-projects, or **--long** | global_tenant=True | |
--deleted, --hidden, --nested | show_deleted=True, show_hidden=True, show_nested=True | |
--project | tenant=<id>, after a Keystone lookup [read: heatclient/osc/v1/stack.py:705-706; the probe stopped at the lookup] | |
stack show | --no-resolve-outputs | resolve_outputs=False |
stack update --dry-run | --show-nested | show_nested=True |
stack event list | always | sort_dir=asc or desc |
--sort k[:dir] | sort_keys=k (:dir alone sends none) | |
--limit, --marker, --nested-depth, --filter k=v | limit, marker, nested_depth, k=v | |
stack resource list | -n, --long, --filter k=v | nested_depth, with_detail=True, k=v |
stack resource show | --with-attr a repeated | with_attr=a&with_attr=b |
orchestration resource type list | --long, --filter | with_description=True or False, k=v |
orchestration resource type show | --long; --template-type | with_description=…; template_type=hot on /template |
orchestration template function list | --with_conditions | with_condition_func=True or False |
orchestration template validate | --show-nested, --ignore-errors | show_nested=True, ignore_errors=99001,99002 in the query, not the body |
software config list | --limit, --marker | limit, marker |
software deployment list | --server | server_id |
Request bodies [observed]
POST /stacks
{"stack_name": "x", "disable_rollback": true, "parameters": {"a": "b"},
"template": {"heat_template_version": "2013-05-23", "resources": {}},
"files": {}, "environment": {}, "tags": "t1,t2", "timeout_mins": 5}
| Request | Body |
|---|---|
POST /stacks/preview | as POST /stacks |
PUT /stacks/{x} | parameters, template, files, environment; optional environment_files, files_container, tags, timeout_mins, clear_parameters, disable_rollback, converge |
PATCH /stacks/{x} (--existing) | same, with template possibly null |
POST /stacks (adopt) | stack_name, disable_rollback, adopt_stack_data as a string, parameters, files, environment, timeout |
POST /stacks/{x}/actions | one key with a null value: suspend, resume, check, cancel_update, cancel_without_rollback |
POST /validate | template, parameters, files, environment; optional environment_files, files_container |
POST …/signal | the --data dict; JSON null without data; {"unset_hook": "pre-create"} for hooks |
PATCH …/resources/{r} | mark_unhealthy, resource_status_reason |
POST …/snapshots | {} or {"name": "n"} |
POST /software_configs | group, config, inputs, outputs, options, name |
POST /software_deployments | config_id, server_id, action, status: IN_PROGRESS |
tags is a comma-separated string, not a list. Environment files appear in files under their absolute file:// URL, so local paths reach the server [observed in the wire probe variant with -e].
Responses read
The full list of keys is in 07 § 2. Rule: the body counts only if Content-Type contains application/json (heatclient/common/utils.py:436-445). List routes parse JSON regardless (heatclient/common/base.py:113).
Error handling
See 02. No retry; every error ends the command, or the current stack on multi-stack delete.
2. Keystone
- Authentication: by OSC and keystoneauth, not by this package. The plugin only receives the session.
- **
stack list --project**:identity_common.find_project(heatclient/osc/v1/stack.py:586-590) sendsGET /v3/projects/{project}, thenGET /v3/projects?name=[observed].
3. Swift (TempURL for deployments)
software deployment create with TEMP_URL_SIGNAL creates a URL that the server calls to signal its result (heatclient/common/deployment_utils.py:94-115):
PUTthe container, named<deployment>-<uuid>;HEADthe account, andPOSTa randomx-account-meta-temp-url-keyif none exists;- compute an HMAC TempURL for
PUT, valid for--timeoutminutes; PUTan empty object;- put the URL in the derived config as input
deploy_signal_id.
Seen only through heat deployment-create [observed, L02]. **openstack software deployment create fails before step 1** (defect 1). --container exists on the OSC command, but create_temp_url is called without it (heatclient/common/deployment_utils.py:131), so the option has no effect [read in the code].
4. Local files and URLs
| Read | Function | Arguments | Note |
|---|---|---|---|
| template | heatclient/common/template_utils.py:70 | -t | file:// or any URL |
| child files | heatclient/common/utils.py:412 | get_file, type: *.yaml in templates | absolute URL used as key in files |
| environment | heatclient/common/template_utils.py:323 | -e | |
| parameter file | heatclient/common/utils.py:412 | --parameter-file | relative to the template's directory |
| adopt file | heatclient/osc/v1/stack.py:876 | --adopt-file | sent as a string |
| signal data | heatclient/osc/v1/resource.py:238 | --data-file | |
| config files | heatclient/osc/v1/software_config.py:158, heatclient/osc/v1/software_config.py:168 | --definition-file, --config-file | |
| written | heatclient/osc/v1/stack.py:934, heatclient/osc/v1/stack.py:978 | --output-file | mode w, overwrites |
request.urlopen is called with no timeout, so a slow URL can block a command [read in the code]. See defect 13 for what template contents can trigger.
5. Python API
The commands use the managers of heatclient/v1/ directly, and third-party code can do the same through heatclient.client.Client('1', session=…) (heatclient/client.py:17-21). Only http_client.request bypasses managers, in authenticated_fetcher (heatclient/common/http.py:40-50).
Source: reverse-spec-python-heatclient/03-interactions_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.