Allow glob of --host and --yaml; cut release 1.2.1

This commit is contained in:
Pim van Pelt
2025-07-06 23:31:41 +02:00
parent fd74c41fb3
commit 9475d7b5c0
5 changed files with 52 additions and 21 deletions

View File

@ -56,11 +56,11 @@ make build
```bash ```bash
# Backup all devices (multiple YAML files are automatically merged) # Backup all devices (multiple YAML files are automatically merged)
ipng-router-backup --yaml 00-device-types.yaml --yaml config.yaml --output-dir /backup ipng-router-backup --yaml "00-*.yaml" --yaml config.yaml --output-dir /backup
# Backup specific devices # Backup specific devices
ipng-router-backup --yaml 00-device-types.yaml --yaml config.yaml --output-dir /backup \ ipng-router-backup --yaml 00-device-types.yaml --yaml config.yaml --output-dir /backup \
--host asw100 --host "asw*"
``` ```
3. **Check output**: 3. **Check output**:

8
debian/changelog vendored
View File

@ -1,3 +1,11 @@
ipng-router-backup (1.2.1) stable; urgency=low
* Add glob pattern support for --yaml flag (e.g., --yaml "*.yaml")
* Add glob pattern support for --host flag (e.g., --host "asw*")
* Update documentation with glob pattern examples
-- Pim van Pelt <pim@ipng.ch> Sun, 07 Jul 2025 21:00:00 +0100
ipng-router-backup (1.2.0) stable; urgency=low ipng-router-backup (1.2.0) stable; urgency=low
* Add atomic file operations with .new suffix for backup reliability * Add atomic file operations with .new suffix for backup reliability

View File

@ -79,16 +79,20 @@ Files are merged automatically using mergo. Later files override earlier ones:
```bash ```bash
# Load multiple files - later files override earlier ones # Load multiple files - later files override earlier ones
ipng-router-backup --yaml 00-device-types.yaml --yaml config.yaml --yaml overrides.yaml ipng-router-backup --yaml 00-device-types.yaml --yaml config.yaml --yaml overrides.yaml
# Load files using glob patterns
ipng-router-backup --yaml "*.yaml"
ipng-router-backup --yaml "config/*.yaml"
``` ```
## Command Line Usage ## Command Line Usage
### Required Flags ### Required Flags
- **`--yaml`**: Path to YAML configuration file(s) (can be repeated) - **`--yaml`**: Path to YAML configuration file(s) or glob patterns (can be repeated)
### Optional Flags ### Optional Flags
- **`--output-dir`**: Output directory (default: `/tmp`) - **`--output-dir`**: Output directory (default: `/tmp`)
- **`--host`**: Specific hostname(s) to process (can be repeated) - **`--host`**: Specific hostname(s) or glob patterns to process (can be repeated)
- **`--password`**: SSH password - **`--password`**: SSH password
- **`--key-file`**: SSH private key file path - **`--key-file`**: SSH private key file path
- **`--port`**: SSH port (default: `22`) - **`--port`**: SSH port (default: `22`)
@ -96,14 +100,14 @@ ipng-router-backup --yaml 00-device-types.yaml --yaml config.yaml --yaml overrid
### Examples ### Examples
```bash ```bash
# Basic usage # Basic usage with glob patterns
ipng-router-backup --yaml config.yaml ipng-router-backup --yaml "*.yaml"
# Multiple files # Multiple files
ipng-router-backup --yaml 00-device-types.yaml --yaml config.yaml ipng-router-backup --yaml 00-device-types.yaml --yaml config.yaml
# Specific devices only # Devices matching patterns
ipng-router-backup --yaml config.yaml --host asw100 --host core-01 ipng-router-backup --yaml config.yaml --host "asw*" --host "*switch*"
# Custom output directory # Custom output directory
ipng-router-backup --yaml config.yaml --output-dir /backup/network ipng-router-backup --yaml config.yaml --output-dir /backup/network

View File

@ -18,7 +18,7 @@ The tool supports multiple device types with predefined command sets, SSH agent
.SH OPTIONS .SH OPTIONS
.TP .TP
.BR --yaml " \fICONFIG_FILE\fR" .BR --yaml " \fICONFIG_FILE\fR"
YAML configuration file(s) (required) YAML configuration file(s) or glob patterns (required)
.TP .TP
.BR --output-dir " \fIDIRECTORY\fR" .BR --output-dir " \fIDIRECTORY\fR"
Output directory for command output files (default: /tmp) Output directory for command output files (default: /tmp)
@ -33,7 +33,7 @@ SSH private key file path
SSH port number (default: 22) SSH port number (default: 22)
.TP .TP
.BR --host " \fIHOSTNAME\fR" .BR --host " \fIHOSTNAME\fR"
Specific host(s) to process (can be repeated, processes all if not specified) Specific host(s) or glob patterns to process (can be repeated, processes all if not specified)
.TP .TP
.BR --help .BR --help
Show help message Show help message
@ -72,9 +72,9 @@ Password authentication (--password option)
For each device, a text file named after the hostname is created in the specified directory. Each command output is prefixed with "## COMMAND: <command_name>" for easy identification. For each device, a text file named after the hostname is created in the specified directory. Each command output is prefixed with "## COMMAND: <command_name>" for easy identification.
.SH EXAMPLES .SH EXAMPLES
.TP .TP
Basic usage: Basic usage with glob patterns:
.EX .EX
ipng-router-backup --yaml /etc/ipng-router-backup/*.yaml ipng-router-backup --yaml "*.yaml"
.EE .EE
.TP .TP
Custom output directory: Custom output directory:
@ -87,9 +87,9 @@ Using password authentication:
ipng-router-backup --yaml config.yaml --password mysecretpass ipng-router-backup --yaml config.yaml --password mysecretpass
.EE .EE
.TP .TP
Process specific hosts only: Process hosts matching patterns:
.EX .EX
ipng-router-backup --yaml config.yaml --host asw100 --host asw120 ipng-router-backup --yaml config.yaml --host "asw*" --host "*switch*"
.EE .EE
.SH FILES .SH FILES
.TP .TP

View File

@ -6,11 +6,12 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"path/filepath"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
const Version = "1.2.0" const Version = "1.2.1"
// Config and SSH types are now in separate packages // Config and SSH types are now in separate packages
@ -36,8 +37,21 @@ func main() {
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("IPng Networks Router Backup v%s\n", Version) fmt.Printf("IPng Networks Router Backup v%s\n", Version)
// Expand glob patterns in YAML files
var expandedYamlFiles []string
for _, pattern := range yamlFiles {
matches, err := filepath.Glob(pattern)
if err != nil {
log.Fatalf("Invalid glob pattern '%s': %v", pattern, err)
}
if len(matches) == 0 {
log.Fatalf("No files matched pattern '%s'", pattern)
}
expandedYamlFiles = append(expandedYamlFiles, matches...)
}
// Load configuration // Load configuration
cfg, err := ConfigRead(yamlFiles) cfg, err := ConfigRead(expandedYamlFiles)
if err != nil { if err != nil {
log.Fatalf("Failed to load config: %v", err) log.Fatalf("Failed to load config: %v", err)
} }
@ -63,11 +77,16 @@ func main() {
devicesToProcess := cfg.Devices devicesToProcess := cfg.Devices
if len(hostFilter) > 0 { if len(hostFilter) > 0 {
devicesToProcess = make(map[string]Device) devicesToProcess = make(map[string]Device)
for _, hostname := range hostFilter { for _, pattern := range hostFilter {
if deviceConfig, exists := cfg.Devices[hostname]; exists { patternMatched := false
devicesToProcess[hostname] = deviceConfig for hostname, deviceConfig := range cfg.Devices {
} else { if matched, _ := filepath.Match(pattern, hostname); matched {
fmt.Printf("Warning: Host '%s' not found in config file\n", hostname) devicesToProcess[hostname] = deviceConfig
patternMatched = true
}
}
if !patternMatched {
fmt.Printf("Warning: Host pattern '%s' did not match any devices\n", pattern)
} }
} }
} }