Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,17 @@ rostr add
# Generate configs
rostr sync

# The base directory (BASE_DIR) is determined as:
# - If ROSTR_HOME is set: $ROSTR_HOME
# - If XDG_CONFIG_HOME is set: $XDG_CONFIG_HOME/rostr
# - Otherwise: ~/.rostr

# Set BASE_DIR for use in commands below
BASE_DIR="${ROSTR_HOME:-${XDG_CONFIG_HOME:+$XDG_CONFIG_HOME/rostr}}"
BASE_DIR="${BASE_DIR:-$HOME/.rostr}"

# Include in your SSH config
echo "Include ~/.rostr/generated/ssh_config" >> ~/.ssh/config
echo "Include $BASE_DIR/generated/ssh_config" >> ~/.ssh/config
```

## Usage
Expand Down Expand Up @@ -108,7 +117,11 @@ rostr setup automation # Configure cloud-init registration
## Directory Structure

```
~/.rostr/
# Set BASE_DIR for reference
BASE_DIR="${ROSTR_HOME:-${XDG_CONFIG_HOME:+$XDG_CONFIG_HOME/rostr}}"
BASE_DIR="${BASE_DIR:-$HOME/.rostr}"

$BASE_DIR/
├── config.yaml # Configuration
├── inventory/
│ ├── _defaults.yaml # Default values
Expand Down Expand Up @@ -150,7 +163,11 @@ servers:
### SSH Config

```
# ~/.rostr/generated/ssh_config
# Set BASE_DIR for reference
BASE_DIR="${ROSTR_HOME:-${XDG_CONFIG_HOME:+$XDG_CONFIG_HOME/rostr}}"
BASE_DIR="${BASE_DIR:-$HOME/.rostr}"

# $BASE_DIR/generated/ssh_config
Host web-prod-01
HostName 10.0.1.10
User admin
Expand All @@ -165,7 +182,11 @@ Groups are auto-generated by:
- Notes: `notes_primary`

```bash
ansible -i ~/.rostr/generated/ansible-inventory.yaml tag_webserver -m ping
# Set BASE_DIR for reference
BASE_DIR="${ROSTR_HOME:-${XDG_CONFIG_HOME:+$XDG_CONFIG_HOME/rostr}}"
BASE_DIR="${BASE_DIR:-$HOME/.rostr}"

ansible -i $BASE_DIR/generated/ansible-inventory.yaml tag_webserver -m ping
```

## Configuration
Expand Down
3 changes: 2 additions & 1 deletion docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ These are applied when adding servers if not explicitly specified.

| Variable | Description | Default |
|----------|-------------|---------|
| `ROSTR_HOME` | Base directory | `~/.rostr` |
| `ROSTR_HOME` | Base directory | `$XDG_CONFIG_HOME/rostr` or `~/.rostr` |
| `XDG_CONFIG_HOME` | XDG config directory | `~/.config` |
| `ROSTR_UPTIMEKUMA_SSH_HOST` | SSH host override | From config |
| `ROSTR_UPTIMEKUMA_DOCKER_CMD` | Docker command path | `docker` |
| `ROSTR_UPTIMEKUMA_DB_USER` | Database username | `kuma` |
Expand Down
28 changes: 20 additions & 8 deletions src/rostr/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import logging
import os
import re
import shutil
import subprocess
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
Expand Down Expand Up @@ -43,12 +44,15 @@
# Initialize Rich console with theme
console = Console(theme=CATPPUCCIN)

# Determine base directory from environment or default to ~/.rostr
# Determine base directory from environment or default
def get_base_dir() -> Path:
"""Get base directory from ROSTR_HOME environment variable or default."""
"""Get base directory from environment or default."""
env_home = os.environ.get("ROSTR_HOME")
if env_home:
return Path(env_home).expanduser()
xdg_config = os.environ.get("XDG_CONFIG_HOME")
if xdg_config:
return Path(xdg_config) / "rostr"
return Path.home() / ".rostr"

BASE_DIR = get_base_dir()
Expand Down Expand Up @@ -517,6 +521,14 @@ def init(ctx):
"""Initialize rostr in the current or default directory."""
console.print("[primary]Welcome to rostr![/primary]\n")

# Check for migration from old .rostr location
old_base = Path.home() / ".rostr"
if old_base.exists() and not BASE_DIR.exists() and os.environ.get("XDG_CONFIG_HOME"):
if Confirm.ask(f"Found existing rostr config at {old_base}. Would you like to migrate to the new XDG location {BASE_DIR}?", default=True):
shutil.copytree(old_base, BASE_DIR)
console.print(f"[success]✓[/success] Migrated from {old_base} to {BASE_DIR}")
console.print("You can now remove the old directory if desired.\n")

# Check if already initialized
if CONFIG_FILE.exists():
if not Confirm.ask(f"rostr is already initialized at {BASE_DIR}. Reinitialize?", default=False):
Expand Down Expand Up @@ -553,7 +565,7 @@ def init(ctx):
console.print(f" [success]✓[/success] {DEFAULTS_FILE}")

# Create config file
config_content = """# rostr configuration
config_content = f"""# rostr configuration
# See docs/CONFIGURATION.md for all options

defaults:
Expand Down Expand Up @@ -585,10 +597,10 @@ def init(ctx):
enabled: false

paths:
inventory: ~/.rostr/inventory
generated: ~/.rostr/generated
backups: ~/.rostr/backups
logs: ~/.rostr/logs
inventory: {BASE_DIR}/inventory
generated: {BASE_DIR}/generated
backups: {BASE_DIR}/backups
logs: {BASE_DIR}/logs
"""
if not CONFIG_FILE.exists():
with open(CONFIG_FILE, "w") as f:
Expand Down Expand Up @@ -669,7 +681,7 @@ def init(ctx):
"1. Edit config.yaml with your settings",
"2. Add your first server: [cyan]rostr add[/cyan]",
"3. Generate configs: [cyan]rostr sync[/cyan]",
"4. Include in SSH: [dim]echo \"Include ~/.rostr/generated/ssh_config\" >> ~/.ssh/config[/dim]",
f"4. Include in SSH: [dim]echo \"Include {BASE_DIR}/generated/ssh_config\" >> ~/.ssh/config[/dim]",
])

console.print("\n[primary]Next steps:[/primary]")
Expand Down
8 changes: 4 additions & 4 deletions src/rostr/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ def generate_cloud_init_template(webhook_url: str, token: str, default_group: st
def save_cloud_init_templates(webhook_url: str, token: str, groups: list[str],
ssh_pubkey: str, username: str) -> list[Path]:
"""Generate and save cloud-init template for each group."""
from rostr.cli import GENERATED_DIR
from rostr.cli import BASE_DIR, GENERATED_DIR

output_dir = Path(GENERATED_DIR) / "cloud-init"
output_dir.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -881,7 +881,7 @@ def generate_n8n_workflow(

def save_n8n_workflow(workflow: dict) -> Path:
"""Save n8n workflow JSON to generated directory."""
from rostr.cli import GENERATED_DIR
from rostr.cli import BASE_DIR, GENERATED_DIR

output_dir = Path(GENERATED_DIR) / "n8n"
output_dir.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -1179,8 +1179,8 @@ def automation():

console.print()
console.print("[bold]Quick Reference:[/bold]")
console.print(" Cloud-init templates: [cyan]~/.rostr/generated/cloud-init/[/cyan]")
console.print(" n8n workflow: [cyan]~/.rostr/generated/n8n/server-registration-workflow.json[/cyan]")
console.print(f" Cloud-init templates: [cyan]{BASE_DIR}/generated/cloud-init/[/cyan]")
console.print(f" n8n workflow: [cyan]{BASE_DIR}/generated/n8n/server-registration-workflow.json[/cyan]")
console.print(f" Webhook URL: [cyan]{webhook_url}[/cyan]")
console.print(f" Groups: [cyan]{', '.join(groups)}[/cyan]")
console.print(f" SSH user: [cyan]{cloud_username}[/cyan]")
Expand Down