Skip to content

Add execute_command service for running arbitrary commands inside Docker containers#46

Merged
gensyn merged 6 commits intomainfrom
copilot/add-service-execute-commands
Mar 27, 2026
Merged

Add execute_command service for running arbitrary commands inside Docker containers#46
gensyn merged 6 commits intomainfrom
copilot/add-service-execute-commands

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 27, 2026

Adds a new HA service that executes an arbitrary command inside a Docker container on the remote host, identified by sensor entity ID, and returns the output.

Changes

  • const.py — new SERVICE_EXECUTE_COMMAND = "execute_command" constant
  • coordinator.pyexecute_command(command: str, timeout: int = DEFAULT_TIMEOUT) -> tuple[str, int] method using docker exec <container> sh -c <cmd> 2>&1; both container name and command are shlex.quote()-escaped; timeout is forwarded to _ssh_run
  • __init__.py — registers the service with entity_id + command + optional timeout schema; returns {"output": ..., "exit_status": ...} (SupportsResponse.ONLY)
  • services.yaml / strings.json / translations/en.json / translations/de.json — service metadata and translations, including the new timeout field
  • README.md — documents the execute_command service (and previously undocumented refresh / get_logs services)
  • tests/playwright/mock-docker.sh — new exec case handles flags, validates the container is running, and executes the command with correct exit code propagation
  • tests/playwright/test_services.py — new TestExecuteCommand class with four Playwright E2E tests covering successful output, non-zero exit codes, the timeout parameter, and missing-field validation; test_services_registered updated to expect execute_command
  • tests/unit_tests/test_init.pyTestExecuteCommandTimeout class with unit tests covering default and custom timeout forwarding to _ssh_run
  • tests/integration_tests/test_integration.pyTestServicesRegistered extended with test_get_logs_service_registered and test_execute_command_service_registered; TestServiceMechanics extended with three integration tests covering successful output/exit_status, timeout forwarding, and non-zero exit code capture

Usage

action: ssh_docker.execute_command
data:
  entity_id: sensor.my_container
  command: "cat /etc/os-release"
  timeout: 30   # optional — seconds to wait (default: 60, max: 3600)

Response:

{ "output": "NAME=\"Alpine Linux\"\n...", "exit_status": 0 }

⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.

Copilot AI changed the title [WIP] Add service to execute commands in docker container by sensor ID Add execute_command service for running arbitrary commands inside Docker containers Mar 27, 2026
Copilot AI requested a review from gensyn March 27, 2026 08:38
@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 27, 2026

@copilot Please also update README.md to include the new service.

…refresh/get_logs entries

Agent-Logs-Url: https://github.com/gensyn/ssh_docker/sessions/f5bf918a-0a29-47ae-a9f6-656b36210ba4

Co-authored-by: gensyn <36128035+gensyn@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 27, 2026

@copilot Please also update README.md to include the new service.

Done in ac70e7e. Added ssh_docker.execute_command to the Services section of the README with a usage example and description of the response fields (output, exit_status). Also added the previously undocumented refresh and get_logs services while there.

@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 27, 2026

@copilot Add an optional timeout parameter.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 27, 2026

@copilot Add an optional timeout parameter.

Done in 3d2fc0c. Added an optional timeout integer field (default: 60, max: 3600 seconds) to execute_command across all layers:

  • coordinator.pyexecute_command(command, timeout=DEFAULT_TIMEOUT) forwards to _ssh_run
  • __init__.py — schema: vol.Optional("timeout"): vol.All(int, vol.Range(min=1))
  • services.yamlnumber selector (1–3600 s)
  • strings.json / translations/en.json / translations/de.json — translated field labels
  • README.md — documents the parameter in the usage example

@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 27, 2026

@copilot Please add a Playwright test to test the new service. Is any other functionality untested by Playwright?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 27, 2026

@copilot Please add a Playwright test to test the new service. Is any other functionality untested by Playwright?

Done in 2a6490b. Added a TestExecuteCommand class in test_services.py with four tests:

  • test_execute_command_returns_output_and_exit_status — runs echo hello, asserts output contains "hello" and exit_status is 0
  • test_execute_command_captures_nonzero_exit_status — runs exit 42, asserts exit_status is 42
  • test_execute_command_with_explicit_timeout — passes timeout: 30, asserts the call succeeds
  • test_execute_command_requires_command_field — omits command, asserts 400/422 validation error

Also added exec support to mock-docker.sh (validates container exists and is running, then executes the command via "$@" with correct exit code propagation), and added execute_command to the test_services_registered expected set.

Other functionality currently untested by Playwright:

  • create service — requires the docker_create executable which isn't present on the mock host, so it can't be exercised end-to-end without extending the test environment
  • The update entity — present and registered but no Playwright test exercises the update available/install flow

@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 27, 2026

@copilot What about unit and integration tests?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 27, 2026

@copilot What about unit and integration tests?

Done in a54e734. Here's the full picture:

Unit tests — already had TestExecuteCommandTimeout covering default and custom timeout forwarding to _ssh_run.

Integration tests (added in a54e734):

  • TestServicesRegistered — added test_get_logs_service_registered and test_execute_command_service_registered (both were missing)
  • TestServiceMechanics — added three tests:
    • test_execute_command_returns_output_and_exit_status — calls the service via a real HA instance, verifies a docker exec SSH command is issued and the response contains the correct output and exit_status 0
    • test_execute_command_forwards_timeout — verifies the timeout parameter is forwarded to _ssh_run
    • test_execute_command_captures_nonzero_exit_status — verifies non-zero exit codes appear in the service response

All 75 unit tests and 72 integration tests pass.

@gensyn gensyn marked this pull request as ready for review March 27, 2026 09:34
@gensyn gensyn merged commit 9ee24ae into main Mar 27, 2026
5 checks passed
@gensyn gensyn deleted the copilot/add-service-execute-commands branch March 27, 2026 09:34
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