# LXD Container Management Tool (lxcmgt)

A command-line tool for automating the setup and configuration of LXD containers with cloud-init, static IP assignment, environment variables, and SSH key management.

## Features

- 🚀 **Automated Container Setup**: Create and configure LXD containers in a single command
- 📋 **Profile Management**: Create/update LXD profiles with embedded or custom YAML configurations
- 🌐 **Static IP Assignment**: Configure static IP addresses for containers
- 🔐 **Environment Variables**: Set container environment variables from `.env` files
- 🔑 **SSH Key Management**: Automatically install SSH authorized keys
- 🎯 **Project Support**: Work with LXD projects for multi-tenant environments
- 🌉 **Custom Bridges**: Configure custom network bridges
- 🔄 **Network Management**: Restart LXD network daemon and flush iptables

## Installation

### Prerequisites

- Rust 1.70+ and Cargo
- LXD installed and configured
- Appropriate LXD permissions

### Build from Source

```bash
git clone https://github.com/JeanMaximilienCadic/lxcmgt
cd lxcmgt
cargo build --release
```

The binary will be available at `target/release/lxcmgt`.

### Install via Cargo

```bash
cargo install --path .
```

## Usage

### Show Help

```bash
lxcmgt
# or
lxcmgt --help
```

### Display Default Configuration

```bash
# Show the embedded default profile YAML configuration
lxcmgt show-config
```

### Restart LXD Network

```bash
# Restart LXD network daemon and flush iptables
lxcmgt restart-network
```

This command will:
- Flush all iptables rules (iptables, iptables-legacy, ip6tables, ip6tables-legacy)
- Reload the snap.lxd.daemon service
- Restart the lxd.daemon snap service

**Note**: This command requires root/sudo privileges.

### Basic Usage

```bash
# Build container with default settings (requires lxd/.env file)
lxcmgt build --env-file lxd/.env

# Build container using an existing LXD profile (skips env file validation)
lxcmgt build --from-config my-existing-profile
```

### Custom Configuration

```bash
# Custom project and container
lxcmgt build \
  --project myproject \
  --container mycontainer \
  --env-file lxd/.env

# Custom bridge network
lxcmgt build \
  --bridge mybridge \
  --env-file lxd/.env

# Custom IP address
lxcmgt build \
  --container-ip 10.2.0.100 \
  --env-file lxd/.env

# Custom container image
lxcmgt build \
  --image ubuntu:22.04 \
  --env-file lxd/.env

# Use custom profile YAML file
lxcmgt build --profile-yaml /path/to/custom.yaml

# Use existing LXD profile (skips env file and profile YAML validation)
lxcmgt build --from-config my-existing-profile
```

### Full Example

```bash
lxcmgt build \
  --project myproject \
  --container mycontainer \
  --container-ip 10.2.0.100 \
  --bridge lxdbr1 \
  --image ubuntu:24.04 \
  --env-file /path/to/.env \
  --profile-yaml /path/to/profile.yaml
```

## Command-Line Arguments

| Argument | Environment Variable | Default | Description |
|----------|---------------------|---------|-------------|
| `--project` | `PROJECT` | `default` | LXD project name |
| `--container` | `CONTAINER` | `default-dev` | Container name |
| `--container-ip` | `CONTAINER_IP` | `10.2.0.2` | Container IP address |
| `--bridge` | `BRIDGE` | `lxdbr0` | Network bridge name |
| `--image` | `IMAGE` | `ubuntu:24.04` | Container image (e.g., ubuntu:24.04, ubuntu:22.04) |
| `--profile-yaml` | `PROFILE_YAML` | (none) | Path to custom profile YAML file |
| `--env-file` | `ENV_FILE` | `lxd/.env` | Path to environment variables file |
| `--from-config` | `FROM_CONFIG` | (none) | Existing LXD profile name to reuse |

### Commands

| Command | Description |
|---------|-------------|
| `build` | Build and configure the LXD container |
| `show-config` | Display the default embedded profile YAML configuration |
| `restart-network` | Restart LXD network daemon and flush iptables |

## Environment Variables

All command-line arguments can be set via environment variables:

```bash
export PROJECT=myproject
export CONTAINER=mycontainer
export CONTAINER_IP=10.2.0.100
export BRIDGE=lxdbr1
export IMAGE=ubuntu:24.04
export ENV_FILE=/path/to/.env
export PROFILE_YAML=/path/to/profile.yaml
export FROM_CONFIG=my-existing-profile

lxcmgt build
```

## Configuration Files

### Using Existing LXD Profile

You can reuse an existing LXD profile that's already configured in your LXD instance. This skips the env file and profile YAML validation.

**Usage**:
```bash
# Use an existing profile named "my-profile"
lxcmgt build --from-config my-profile

# The profile must exist in the specified project
lxcmgt build --project myproject --from-config my-profile
```

When using `--from-config`, the tool will:
- Verify the profile exists in the specified project
- Skip environment file validation
- Skip profile YAML updates
- Skip environment variable setup
- Use the existing profile when initializing the container

### Environment File Format

The environment file (`.env`) should contain `KEY=VALUE` pairs:

```bash
# lxd/.env
DATABASE_URL=postgresql://localhost/mydb
API_KEY=secret-key-123
DEBUG=true
```

### Profile YAML

When using the default embedded profile, the tool uses a pre-configured YAML template that includes:
- Cloud-init configuration
- User creation (`foo` user)
- Package installation (git, docker, cargo, etc.)
- Custom initialization scripts

You can provide a custom profile YAML file using `--profile-yaml`:

```bash
lxcmgt build --profile-yaml /path/to/custom-profile.yaml
```

### SSH Keys

Place SSH public keys in `lxd/authorized_keys` (one per line). The tool will automatically install them for the `foo` user.

## Requirements

### Default Profile Mode

When using the default embedded profile (`--profile-yaml` not specified):
- The `--env-file` argument is **REQUIRED**
- The environment file must exist and contain valid `KEY=VALUE` pairs
- The tool will validate the env file **before** creating any containers

### Custom Profile Mode

When using a custom profile YAML (`--profile-yaml` specified):
- The `--env-file` argument is **optional**
- Environment variables can be configured in the YAML file itself
- The env file validation is skipped

### Existing Profile Mode

When using `--from-config`:
- Both `--env-file` and `--profile-yaml` validation are **skipped**
- The specified LXD profile must exist in the project
- Environment variable setup is skipped (assumes they're configured in the profile)
- The existing profile is used when initializing the container
- This is useful for reusing existing LXD profile configurations

## Workflow

### Build Command Workflow

The `build` command performs the following steps:

1. **Validate Environment File** (if using default profile)
2. **Delete Container** (if it exists)
3. **Update Profile** (create or update the default profile)
4. **Initialize Container** (create new container from specified image)
5. **Set Static IP** (configure network interface)
6. **Set Credentials** (configure environment variables)
7. **Start Container** (start the container)
8. **Wait for Ready** (wait for container to be ready)
9. **Set SSH Keys** (install authorized keys)

### Restart Network Command Workflow

The `restart-network` command performs the following steps:

1. **Flush iptables** (for all variants: iptables, iptables-legacy, ip6tables, ip6tables-legacy)
2. **Reload snap.lxd.daemon** (reload systemd service)
3. **Restart lxd.daemon** (restart snap service)

## Examples

### Example 1: Basic Setup

```bash
# Create lxd/.env file
cat > lxd/.env << EOF
DATABASE_URL=postgresql://localhost/mydb
API_KEY=my-secret-key
EOF

# Build container
lxcmgt build --env-file lxd/.env
```

### Example 2: Custom Project

```bash
lxcmgt build \
  --project production \
  --container app-server \
  --container-ip 10.2.0.50 \
  --env-file lxd/.env
```

### Example 3: Custom Profile

```bash
lxcmgt build \
  --profile-yaml /path/to/my-profile.yaml \
  --container mycontainer
```

### Example 4: Using Existing LXD Profile

```bash
# Use an existing LXD profile that's already configured
lxcmgt build \
  --project production \
  --container app-server \
  --container-ip 10.2.0.50 \
  --from-config my-existing-profile
```

### Example 5: Custom Container Image

```bash
# Use a different Ubuntu version
lxcmgt build \
  --image ubuntu:22.04 \
  --env-file lxd/.env

# Use a different base image
lxcmgt build \
  --image alpine:latest \
  --env-file lxd/.env
```

### Example 6: View Default Configuration

```bash
# Display the embedded default profile YAML
lxcmgt show-config > lxd/default-profile.yaml
```

### Example 7: Restart LXD Network

```bash
# Restart LXD network daemon and flush iptables
# Useful when experiencing network issues or after iptables changes
sudo lxcmgt restart-network
```

## Troubleshooting

### Environment File Not Found

If you see an error about the environment file not being found:

```
❌ Error: Environment file not found at "lxd/.env"
```

**Solution**: Either:
- Create the `lxd/.env` file with your environment variables, or
- Specify a custom path: `lxcmgt build --env-file /path/to/.env`, or
- Use a custom profile YAML: `lxcmgt build --profile-yaml /path/to/profile.yaml`

### Container Already Exists

The tool automatically deletes existing containers before creating new ones. If you encounter issues, manually delete the container first:

```bash
lxc delete <container-name> --force --project <project-name>
```

### Permission Errors

Ensure you have appropriate LXD permissions:

```bash
# Add your user to the lxd group
sudo usermod -aG lxd $USER
# Log out and log back in
```

## Development

### Building

```bash
cargo build
```

### Running Tests

```bash
cargo test
```

### Running in Development Mode

```bash
cargo run -- build --env-file lxd/.env
```
