Run Command Service is a lightweight, configurable HTTP service that executes predefined shell commands. It provides a secure way to trigger command execution via HTTP requests, making it useful for various automation and integration scenarios.
- Run Command Service
- Execute predefined shell commands via HTTP requests
- Configurable through environment variables and a YAML configuration file
- Secure execution with secret-based authentication
- Pass request body data to commands as environment variables
- Docker support for easy deployment
- Customizable shell and listening port
- Returns command exit codes for easy integration
- Option to run commands in the background
- Run-once mode for single command execution
- Go 1.20 or later
- Docker (optional, for containerized deployment)
-
Clone the repository:
git clone https://github.com/trigo-at/run-command-service.git cd run-command-service -
Build the binary:
go build -o run-command-service
The service can be configured using the following environment variables:
RCS_CONFIG_FILE_PATH: Path to the YAML configuration file (default:./config.yaml)RCS_EXECUTE_SECRET: Secret key for authentication (required)RCS_SHELL_PATH: Path to the shell used for executing commands (default:/bin/sh)RCS_LISTEN_PORT: Port on which the service listens (default:8080)
The service uses a YAML configuration file to define the command to be executed and its execution mode. By default, it looks for config.yaml in the same directory as the executable.
Example config.yaml:
command: |
echo "Hello from Run Command Service!"
echo "Current date: $(date)"
echo "Request data: $REQUEST_DATA"
runInBackground: false
runOnce: falsecommand: The shell command to be executed.runInBackground: If set totrue, the command will be spawned as a background process.runOnce: If set totrue, the service will execute the command once at startup and exit, using the command's exit code as its own.
Note: runInBackground and runOnce cannot both be set to true as they are mutually exclusive options.
-
Set the required environment variables:
export RCS_EXECUTE_SECRET=your_secret_here -
Run the service:
./run-command-service
The service will start and display the configured command without executing it.
- Description: Checks if the service is running
- Response:
- Status Code: 200 OK
- Content-Type: application/json
- Body: JSON object indicating the service is running
{"status": "ok"}
- Description: Executes the configured command
- Headers:
x-secret: The secret key for authentication (must matchRCS_EXECUTE_SECRET)
- Request Body: Optional. Any data in the request body will be passed to the command as the
REQUEST_DATAenvironment variable. - Response:
- For foreground execution (
runInBackground: false):- Status Code:
- 200 OK if the command executed successfully (exit code 0)
- 500 Internal Server Error if the command failed (non-zero exit code)
- Body: JSON object containing the exit code
{"exit_code": 0}
- Status Code:
- For background execution (
runInBackground: true):- Status Code:
- 200 OK if the process was successfully spawned
- 409 Conflict if a background process is already running
- Body: JSON object indicating the status
or
{"status": "Process spawned successfully"}{"status": "job still running in background"}
- Status Code:
- For foreground execution (
The service can pass data from the request body to the command being executed. This is useful for webhook integrations, such as receiving alerts from monitoring systems or events from other services.
-
Send data in the request body:
curl -X POST -H "x-secret: your_secret_here" \ -d '{"key":"value","alert":"high_cpu"}' \ http://localhost:8080/execute
-
Access the data in your command:
# config.yaml command: | echo "Received data: $REQUEST_DATA" # For JSON data, you can use jq to parse it # echo $REQUEST_DATA | jq -r '.alert'
The entire request body is made available to your command as the REQUEST_DATA environment variable. If you're working with JSON data, you can use tools like jq in your command to parse and extract specific fields.
Example for handling Alertmanager webhooks:
command: |
# Extract alert information
ALERT_NAME=$(echo $REQUEST_DATA | jq -r '.commonLabels.alertname')
SEVERITY=$(echo $REQUEST_DATA | jq -r '.commonLabels.severity')
NAMESPACE=$(echo $REQUEST_DATA | jq -r '.commonLabels.namespace')
# Log the alert
echo "Received alert: $ALERT_NAME with severity $SEVERITY in namespace $NAMESPACE"
# Take action based on the alert
if [ "$SEVERITY" = "critical" ]; then
echo "Taking emergency action for critical alert!"
# Add your critical response commands here
fiYou can run the Run Command Service using a pre-built Docker image from the GitHub Container Registry (ghcr.io) or build your own image. The service supports multiple architectures, including amd64 and arm64.
The Dockerfile uses a multi-stage build process that includes running unit tests and supports multi-architecture builds:
- The first stage builds the application and runs unit tests.
- The second stage creates a lean production image with only the necessary components.
To build the Docker image for your current architecture:
docker build -t run-command-service .To build for multiple architectures using buildx:
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t run-command-service --push .This process ensures that:
- Unit tests are run as part of the build process.
- The final image only contains the production binary, not the test code.
- Images are built for multiple architectures (amd64 and arm64).
To pull the latest version of the Docker image:
docker pull ghcr.io/trigo-at/run-command-service:latestDocker will automatically pull the correct image for your architecture.
You can also pull a specific version or branch of the service by changing the tag:
docker pull ghcr.io/trigo-at/run-command-service:v1.0.0
# or
docker pull ghcr.io/trigo-at/run-command-service:mainAfter pulling the image, you can run it with:
docker run -p 8080:8080 \
-e RCS_EXECUTE_SECRET=your_secret_here \
-e RCS_CONFIG_FILE_PATH=/app/config.yaml \
-v /path/to/your/config.yaml:/app/config.yaml \
ghcr.io/trigo-at/run-command-service:latestMake sure to replace /path/to/your/config.yaml with the actual path to your configuration file on the host machine.
- Keep the
RCS_EXECUTE_SECRETconfidential and use a strong, unique value. - Be cautious about the commands you configure, as they will be executed with the permissions of the user running the service.
- Consider running the service in a restricted environment or container for additional security.
- Use HTTPS in production to encrypt traffic between clients and the service.
- Be aware that any data passed in the request body will be available to the command as an environment variable.
To run the test suite:
go test ./...
A Makefile is provided for common development tasks:
make build: Build the binarymake test: Run testsmake run: Build and run the servicemake docker-build: Build the Docker imagemake docker-run: Run the service in a Docker container
- If the service fails to start, check that all required environment variables are set correctly.
- Verify that the
config.yamlfile is in the correct location and properly formatted. - Check the logs for any error messages or unexpected behavior.
- Ensure that the configured command in
config.yamlis valid and can be executed by the specified shell. - If both
runInBackgroundandrunOnceare set totruein the configuration, the service will return an error as these options are mutually exclusive. - If your command isn't receiving the request body data, make sure you're accessing it using the
$REQUEST_DATAenvironment variable.
For more information or to report issues, please visit the GitHub repository.
Run Command Service is open-source software licensed under the MIT License. See the LICENSE file for more details.
- You are free to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software.
- You must include the copyright notice and the permission notice in all copies or substantial portions of the software.
- The software is provided "as is", without warranty of any kind.
For the full license text, please see the LICENSE file in the repository.