Metadata-Version: 2.4
Name: infranaut
Version: 0.3.0
Summary: GitOps-driven Managed Infrastructure Framework
License: MIT
Keywords: infrastructure,devops,gitops,terraform,opentofu,ansible,terragrunt
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: typer[all]>=0.12
Requires-Dist: jinja2>=3.1
Requires-Dist: rich>=13.0
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: ruff>=0.1; extra == "dev"

# infranaut

**GitOps-driven Managed Infrastructure Framework** — a Python CLI that scaffolds and operates multi-client cloud infrastructure using OpenTofu/Terragrunt + Ansible.

## Overview

infranaut generates and manages the directory structure, Terragrunt HCL files, and Ansible inventories for any number of projects deployed on Hetzner Cloud. Each project contains environments; each environment contains workloads.

```
workspace/
├── .env                    # GIT_USER, GIT_TOKEN, etc.
├── core/                   # Shared Terraform modules & Ansible roles
│   ├── opentofu/
│   └── ansible/
└── projects/
    └── acme/
        ├── opentofu/
        │   ├── _env.hcl
        │   ├── _root.hcl
        │   ├── dev/
        │   │   ├── env.hcl
        │   │   ├── network/
        │   │   └── gitlab/
        │   └── shared/
        │       └── ssh-keys/
        └── ansible/
            ├── ansible.cfg
            └── inventories/
                └── dev/
                    └── gitlab/
```

## Supported workload types

| Type | Description |
|---|---|
| `gitlab` | GitLab CE/EE server |
| `kubernetes_cluster` | Multi-node k8s cluster (controlplanes + workers) |
| `single_node` | Generic standalone server (Mattermost, Nextcloud, …) |
| `multi_node` | Generic primary/secondary cluster |
| `mail_server` | Postfix + Dovecot mail stack |

---

## Installation

### From PyPI (production)

```bash
pip install infranaut
```

### From source (development)

```bash
git clone https://gitlab.kopsengineering.com/ksoft/infrastructur/infranaut_ctl.git
cd infranaut_ctl
pip install -e ".[dev]"
```

---

## Quick start

```bash
# 1 — Create a workspace and pull the shared core
infranaut init /srv/infra --core-provider https://gitlab.example.com/ksoft/infra-core.git

# 2 — Create a project
infranaut project create --name acme

# 3 — Add an environment
infranaut env create --project acme --name dev

# 4 — Add workloads
infranaut workload create --project acme --env dev --type gitlab
infranaut workload create --project acme --env dev --type kubernetes_cluster --name k8s
infranaut workload create --project acme --env dev --type single_node --name mattermost

# 5 — Fill in generated inputs.hcl and env.hcl, then deploy
infranaut deploy --project acme --env dev --workload gitlab

# 6 — Regenerate dynamic inventory after a Terraform apply
infranaut inventory generate --project acme --env dev --workload gitlab
```

---

## Core providers

`--core-provider` controls what goes into `core/` at `infranaut init` time.

| Provider | Effect |
|---|---|
| `empty` *(default)* | Creates an empty `core/` skeleton — add your own modules. |
| `https://…/repo.git` | Clones the repo with `--depth 1` into `core/`. Credentials are read from the workspace `.env` file: `GIT_USER` and `GIT_TOKEN`. |

Git credentials are injected into the HTTPS URL automatically and are never printed to the console.

### `.env` format for git provider

```bash
# workspace/.env
GIT_USER=my-ci-user
GIT_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
```

---

## Commands reference

```
infranaut init [PATH] [--core-provider PROVIDER]
infranaut project create --name NAME
infranaut project list
infranaut env create --project PROJECT --name ENV
infranaut env list --project PROJECT
infranaut workload create --project PROJECT --env ENV --type TYPE [--name NAME]
infranaut workload list --project PROJECT --env ENV
infranaut inventory generate --project PROJECT --env ENV --workload WORKLOAD
infranaut deploy --project PROJECT --env ENV [--workload WORKLOAD]
infranaut version
```

---

## Development workflow

### Prerequisites

- Python 3.11+
- `pip install -e ".[dev]"`

### Run tests

```bash
pytest tests/ -v
```

### Lint

```bash
ruff check infranaut/
ruff format infranaut/
```

### Smoke test (full end-to-end, no cloud)

```bash
mkdir -p /tmp/smoke && cd /tmp/smoke
infranaut init .
infranaut project create --name acme
infranaut env create --project acme --name dev
infranaut workload create --project acme --env dev --type gitlab
infranaut workload create --project acme --env dev --type kubernetes_cluster --name k8s
infranaut workload create --project acme --env dev --type single_node --name mattermost
infranaut workload create --project acme --env dev --type multi_node --name app
infranaut workload create --project acme --env dev --type mail_server
infranaut workload list --project acme --env dev
```

---

## Release workflow

infranaut uses semantic versioning. Releases are triggered by pushing a `vX.Y.Z` tag; GitLab CI builds and publishes to PyPI automatically.

### Steps

**1. Bump the version** in two files:

```python
# infranaut/__init__.py
__version__ = "0.4.0"
```

```toml
# pyproject.toml
version = "0.4.0"
```

**2. Commit and tag:**

```bash
git add infranaut/__init__.py pyproject.toml
git commit -m "chore: bump version to 0.4.0"
git tag v0.4.0
git push origin dev
git push origin v0.4.0
```

The CI pipeline runs automatically:
- `lint` — ruff style check (non-blocking)
- `test` — pytest unit tests
- `smoke-test` — full CLI end-to-end without cloud access
- `publish-pypi` — builds sdist + wheel, publishes to PyPI via `PYPI_TOKEN`

### Required CI/CD variable

In GitLab → Settings → CI/CD → Variables:

| Variable | Type | Description |
|---|---|---|
| `PYPI_TOKEN` | Masked | PyPI API token with `publish` scope |

---

## Test procedure — fresh server

Run this after each release to validate the published package on a clean machine.

```bash
# 1. Install from PyPI (no local checkout)
pip install infranaut==0.4.0

# 2. Verify the CLI is reachable
infranaut version
infranaut --help

# 3. Initialise a workspace with the empty core
mkdir -p /tmp/infra-test && cd /tmp/infra-test
infranaut init .
# Expected: workspace marker created, core/ skeleton present

# 4. Create a project and environment
infranaut project create --name acme
infranaut env create --project acme --name dev
infranaut env create --project acme --name prod

# 5. Create all workload types
infranaut workload create --project acme --env dev --type gitlab
infranaut workload create --project acme --env dev --type kubernetes_cluster --name k8s
infranaut workload create --project acme --env dev --type single_node --name mattermost
infranaut workload create --project acme --env dev --type multi_node --name backend
infranaut workload create --project acme --env dev --type mail_server

# 6. Check the generated tree
find /tmp/infra-test/projects/acme -type f | sort

# 7. Verify key generated files exist and are non-empty
test -f projects/acme/opentofu/_env.hcl                            && echo "OK _env.hcl"
test -f projects/acme/opentofu/dev/env.hcl                         && echo "OK env.hcl"
test -f projects/acme/opentofu/dev/gitlab/terragrunt.hcl           && echo "OK gitlab terragrunt"
test -f projects/acme/opentofu/dev/k8s/terragrunt.hcl              && echo "OK k8s terragrunt"
test -f projects/acme/opentofu/dev/k8s/inputs.hcl                  && echo "OK k8s inputs"
test -f projects/acme/ansible/inventories/dev/gitlab/inventory.yml && echo "OK gitlab inventory"
test -f projects/acme/ansible/inventories/dev/k8s/inventory.yml    && echo "OK k8s inventory"
test -f projects/acme/ansible/inventories/dev/gitlab/site.yml      && echo "OK gitlab site.yml"

# 8. List projects and workloads (CLI consistency check)
infranaut project list
infranaut workload list --project acme --env dev

# 9. Test init with git core provider (requires git + valid token)
mkdir -p /tmp/infra-git && cd /tmp/infra-git
echo "GIT_USER=your-user" > .env
echo "GIT_TOKEN=your-token" >> .env
infranaut init . --core-provider https://gitlab.example.com/your-org/infra-core.git
# Expected: core/ contains the cloned repo content

# 10. Cleanup
rm -rf /tmp/infra-test /tmp/infra-git
```

**What to check after each step:**
- No Python tracebacks
- All `OK` lines printed in step 7
- Generated HCL and YAML files have the correct project/env/workload names substituted
- `ansible.cfg`, `inventories/`, `group_vars/` directories created under `ansible/`

---

## Project structure (infranaut_ctl)

```
infranaut_ctl/
├── infranaut/
│   ├── __init__.py
│   ├── main.py              # CLI entry point (Typer app)
│   ├── config.py            # Constants (workload types, etc.)
│   ├── core_provider.py     # Core init: empty or git clone
│   ├── renderer.py          # Jinja2 template renderer
│   ├── output_bridge.py     # Terraform → Ansible variable bridge
│   ├── commands/
│   │   ├── init.py
│   │   ├── project.py
│   │   ├── env_workload.py
│   │   ├── inventory_cmd.py
│   │   └── deploy.py
│   └── templates/
│       ├── project/
│       │   ├── opentofu/    # _env.hcl, _root.hcl, env.hcl, envrc templates
│       │   └── ansible/     # ansible.cfg template
│       └── workloads/
│           ├── gitlab/
│           ├── kubernetes_cluster/
│           ├── single_node/
│           ├── multi_node/
│           ├── mail_server/
│           ├── network/
│           └── ssh_keys/
├── tests/
├── pyproject.toml
└── .gitlab-ci.yml
```

---

## License

MIT
