Skip to content

Add an osism openstack command that wraps the OpenStack CLI#2392

Open
berendt wants to merge 3 commits into
mainfrom
implement/issue-2391-osism-openstack
Open

Add an osism openstack command that wraps the OpenStack CLI#2392
berendt wants to merge 3 commits into
mainfrom
implement/issue-2391-osism-openstack

Conversation

@berendt

@berendt berendt commented Jun 17, 2026

Copy link
Copy Markdown
Member

Summary

Adds an osism openstack command that transparently wraps the OpenStack
CLI from inside the osism container image. It passes all subcommands and
parameters straight through to the openstack client, defaults to the
admin cloud, and lets the cloud be selected with --cloud.

Credentials are loaded the same way the flavor-manager and image-manager
do — via setup_cloud_environment/get_cloud_helpers from
osism/tasks/openstack.py, which decrypts secrets.yml/secure.yml
from the configuration repository. This removes the need for a separate
openstack container that cannot read the encrypted secure.yml.

The command runs the client in-process (subprocess.run), structurally
mirroring the existing osism openstack stress command, so stdout/stderr
and the exit code pass through unmodified — the behaviour an operator
expects from a transparent wrapper.

Closes #2391

Changes (in commit order)

  1. Declare python-openstackclient runtime dependency
    requirements.txt. The openstack binary the command shells out to
    ships with python-openstackclient, which was not a declared
    dependency (only the openstacksdk library was). Pinned to 9.0.0,
    the highest release compatible with the pinned openstacksdk==4.10.0
    (it requires openstacksdk>=4.6.0; 10.x requires >=4.12.0/>=4.14.0
    and would conflict).
  2. Add and register osism openstack passthrough command
    osism/commands/openstack.py + setup.cfg. The command and its entry
    point land together so the CLI is never half-registered. --os-cloud
    is injected so the client selects the profile whose password
    setup_cloud_environment wrote into the temporary clouds.yaml.
    Both openstack and the existing openstack stress entry points are
    registered; cliff resolves the longest matching command prefix, so
    openstack stress keeps routing to OpenStackStress while
    openstack server list routes to the new command.
  3. Add unit teststests/unit/commands/test_openstack.py. Cover
    argument passthrough with the default admin cloud, --cloud
    selection, the setup-failure short circuit, exit-code propagation, a
    missing openstack binary, and the cliff routing coexistence with
    openstack stress.
  4. Document osism openstack in CHANGELOGCHANGELOG.md.

Notes for reviewers

  • Execution model. The issue says load credentials "the same way the
    flavor-manager and image-manager do," which dispatch a Celery task on
    the openstack worker queue. This change reuses the same credential
    helpers
    but runs the client in-process (like osism openstack stress) rather than via a Celery task. Only the in-process model
    delivers a true transparent wrapper — real exit codes and stdio/TTY
    passthrough; a Celery round-trip would stream output through Redis and
    lose exit-code/interactivity transparency.
  • stress is now a reserved word under osism openstack. Plain
    openstack has no stress subcommand, so nothing real is lost.
  • Working directory. setup_cloud_environment os.chdir("/tmp"), so
    relative paths in passed-through commands resolve against /tmp. This
    is pre-existing behaviour shared with stress/the managers, not
    introduced here.

Drafted by planwerk-review e69a237 with Claude:claude-opus-4-8

The new `osism openstack` command shells out to the `openstack`
CLI, which ships with python-openstackclient. The binary was not a
declared dependency (only the openstacksdk library was), so the
feature would be non-functional in the image without it.

Pin to 9.0.0, the highest release compatible with the pinned
openstacksdk==4.10.0 (it requires openstacksdk>=4.6.0; 10.x requires
>=4.12.0/>=4.14.0).

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Christian Berendt <berendt@osism.tech>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 security issue, 1 other issue, and left some high level feedback:

Security issues:

  • Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. (link)

General comments:

  • In Run.take_action, when setup_cloud_environment returns success=False you return early and never call cleanup_cloud_environment, which may leave temp files or the working directory in an inconsistent state if setup_cloud_environment partially succeeded; consider always invoking cleanup_cloud_environment (e.g. via a try/finally) once setup has been called.
  • The wrapper unconditionally injects --os-cloud <cloud> before the passthrough arguments; if a user also supplies their own --os-cloud in arguments, the resulting behavior may be confusing or order-dependent—consider explicitly rejecting or documenting conflicting --os-cloud usage to avoid ambiguity.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `Run.take_action`, when `setup_cloud_environment` returns `success=False` you return early and never call `cleanup_cloud_environment`, which may leave temp files or the working directory in an inconsistent state if `setup_cloud_environment` partially succeeded; consider always invoking `cleanup_cloud_environment` (e.g. via a `try/finally`) once setup has been called.
- The wrapper unconditionally injects `--os-cloud <cloud>` before the passthrough arguments; if a user also supplies their own `--os-cloud` in `arguments`, the resulting behavior may be confusing or order-dependent—consider explicitly rejecting or documenting conflicting `--os-cloud` usage to avoid ambiguity.

## Individual Comments

### Comment 1
<location path="CHANGELOG.md" line_range="11" />
<code_context>
+## [Unreleased]
+
+### Added
+- `osism openstack` command that runs the OpenStack CLI against a configured cloud (default `admin`), reusing the flavor-/image-manager cloud credential handling (osism/python-osism#2391)
+
 ## [v0.20260319.0] - 2026-03-19
</code_context>
<issue_to_address>
**suggestion (typo):** Consider clarifying the phrase "flavor-/image-manager" for readability.

The hyphen before the slash makes this hard to parse. Consider alternatives like “flavor and image manager”, “flavor/image manager”, or explicitly “flavor-manager/image-manager” to improve readability.

```suggestion
- `osism openstack` command that runs the OpenStack CLI against a configured cloud (default `admin`), reusing the flavor and image manager cloud credential handling (osism/python-osism#2391)
```
</issue_to_address>

### Comment 2
<location path="osism/commands/openstack.py" line_range="49" />
<code_context>
            result = subprocess.run(command, check=False)
</code_context>
<issue_to_address>
**security (python.lang.security.audit.dangerous-subprocess-use-audit):** Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.

*Source: opengrep*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread CHANGELOG.md Outdated
Comment thread osism/commands/openstack.py Outdated
@berendt berendt force-pushed the implement/issue-2391-osism-openstack branch from 3bd12f4 to 42a9f48 Compare June 17, 2026 17:34
berendt added 2 commits June 17, 2026 19:38
Add an `osism openstack` command that transparently wraps the
OpenStack CLI: it passes all subcommands and parameters straight
through to the `openstack` client and propagates its exit code.

Credentials are loaded the same way the flavor-manager and
image-manager do, via setup_cloud_environment/get_cloud_helpers
from osism.tasks.openstack, which decrypts secrets.yml from the
configuration repository. This removes the need for a separate
openstack container that cannot read the encrypted secure.yml.

The command defaults to the admin cloud and selects it explicitly
with --cloud; --os-cloud is injected so the client picks the
profile whose password setup_cloud_environment wrote into the
temporary clouds.yaml.

Register both `openstack` and the existing `openstack stress`
entry points; cliff resolves the longest matching command prefix,
so `openstack stress` keeps routing to OpenStackStress while
`openstack server list` routes to the new command.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Christian Berendt <berendt@osism.tech>
Cover argument passthrough with the default admin cloud, --cloud
selection, the setup-failure short circuit, exit-code propagation,
a missing openstack binary, and cliff longest-prefix routing that
keeps `openstack stress` working alongside the new command.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Christian Berendt <berendt@osism.tech>
@berendt berendt force-pushed the implement/issue-2391-osism-openstack branch from 42a9f48 to 8c88427 Compare June 17, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

Add an osism openstack command that runs the OpenStack CLI against the configured clouds

2 participants