Command Types¶
Clingwrap supports four command types for collecting different kinds of information.
File Commands¶
Copy individual files to the output ZIP.
Syntax¶
Fields¶
| Field | Required | Description |
|---|---|---|
name |
Yes | Human-readable description |
type |
Yes | Must be file |
source |
Yes | Absolute path to the source file |
destination |
Yes | Path within the output ZIP |
Behavior¶
- If the source file exists, it is copied to the ZIP using streaming (memory efficient)
- If the source file is missing, a placeholder is written:
--- file /path/to/file was absent --- - If an error occurs reading the file, the error is captured:
--- file /path/to/file exception: <error> ---
Example¶
- name: System hosts file
type: file
source: /etc/hosts
destination: etc/hosts
- name: Syslog
type: file
source: /var/log/syslog
destination: var/log/syslog
Directory Commands¶
Recursively copy all files in a directory hierarchy.
Syntax¶
- name: Description of the directory
type: directory
source: /path/to/source/directory
destination: path/in/zip
exclude: "optional-regex-pattern"
Fields¶
| Field | Required | Description |
|---|---|---|
name |
Yes | Human-readable description |
type |
Yes | Must be directory |
source |
Yes | Absolute path to the source directory |
destination |
Yes | Base path within the output ZIP |
exclude |
No | Regular expression pattern for files to skip |
Behavior¶
- Walks the directory tree recursively
- Creates a file job for each file found
- Files matching the
excludepattern are skipped - Processes files depth-first for memory efficiency
Exclude Pattern¶
The exclude field accepts a Python regular expression. Files whose full path
matches the pattern are skipped.
Examples:
# Skip disk device files
exclude: "([hsv]d[ac-z]|nvme[0-9])"
# Skip lock files
exclude: ".*\\.lock"
# Skip backup files
exclude: ".*~$"
Example¶
- name: Apache configuration
type: directory
source: /etc/apache2
destination: etc/apache2
- name: Instance data (excluding disk images)
type: directory
source: /srv/shakenfist/instances
destination: srv/shakenfist/instances
exclude: "([hsv]d[ac-z]|nvme[0-9]|sc-.*)"
Shell Commands¶
Execute shell commands and capture their output.
Syntax¶
- name: Description of the command
type: shell
command: shell command to execute
destination: _commands/output-name
Fields¶
| Field | Required | Description |
|---|---|---|
name |
Yes | Human-readable description |
type |
Yes | Must be shell |
command |
Yes | Shell command or script to execute |
destination |
Yes | Path within the output ZIP |
Behavior¶
- Commands are executed in a shell with a 30-second timeout
- Both stdout and stderr are captured
- Output format includes the command and separated stdout/stderr sections
- Exceptions are captured and included in the output
Output Format¶
If an exception occurs:
Multi-line Scripts¶
The command field supports multi-line scripts using YAML block scalars:
- name: Complex diagnostics
type: shell
command: |
echo "System Info"
uname -a
echo ""
echo "Memory Info"
free -h
destination: _commands/system-info
Example¶
- name: Kernel version
type: shell
command: uname -a
destination: _commands/uname
- name: Network interfaces
type: shell
command: ip link
destination: _commands/ip-link
- name: Installed packages
type: shell
command: dpkg -l
destination: _commands/dpkg
Shell Emitter Commands¶
Run shell scripts that dynamically generate additional commands. This is powerful for discovering objects at runtime and creating jobs for each.
Syntax¶
Or with explicit type:
Fields¶
| Field | Required | Description |
|---|---|---|
name |
Yes | Human-readable description |
type |
Yes | Must be shell_emitter |
command |
Yes | Shell script that outputs YAML |
Note: shell_emitter commands do not have a destination field - they
generate other commands that have destinations.
Behavior¶
- Script is executed with a 60-second timeout
- Script stdout must be valid YAML containing command definitions
- Generated commands are processed immediately (depth-first)
- Useful for iterating over dynamic lists (containers, namespaces, etc.)
Output Format¶
The script must output valid YAML command definitions. Each generated command should be a complete command definition with all required fields.
Example: Network Namespaces¶
Discover and collect information from all network namespaces:
- name: Network namespaces
type: shell_emitter
command: |
for item in `find /var/run/netns -type f | sed 's/.*\///'`
do
echo "
- name: Network interfaces (namespace ${item})
type: shell
command: ip netns exec ${item} ip link
destination: _commands/netns-${item}/ip-link
- name: Network routes (namespace ${item})
type: shell
command: ip netns exec ${item} ip route
destination: _commands/netns-${item}/ip-route
"
done
Example: Docker Containers¶
Collect information from all running Docker containers:
- name: Container inspection
type: shell_emitter
command: |
for item in `docker ps --all --format '{{ .Names }}'`
do
echo "
- name: Inspect ${item} container
type: shell
command: docker inspect ${item}
destination: _commands/docker-${item}-inspect
- name: Docker logs for ${item} container
type: shell
command: docker logs --tail 2000 ${item}
destination: _commands/docker-${item}-logs
"
done
Tips for Shell Emitters¶
- Quote YAML properly: Be careful with indentation and quoting in the generated YAML
- Handle empty results: If the loop produces no output, that's fine - no jobs will be generated
- Use echo with heredoc-style output: The example pattern with echo and embedded YAML works well
- Limit output: For log collection, use
--tailor similar to avoid collecting excessive data