Metadata-Version: 2.4
Name: octavia-loxilb-driver
Version: 1.1.0
Summary: LoxiLB provider driver for OpenStack Octavia Load Balancer as a Service
Author-email: OpenStack Community <openstack-discuss@lists.openstack.org>
Maintainer-email: OpenStack Community <openstack-discuss@lists.openstack.org>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/loxilb-io/octavia-loxilb-driver
Project-URL: Documentation, https://github.com/loxilb-io/octavia-loxilb-driver#readme
Project-URL: Repository, https://github.com/loxilb-io/octavia-loxilb-driver.git
Project-URL: Bug Reports, https://github.com/loxilb-io/octavia-loxilb-driver/issues
Project-URL: Changelog, https://github.com/loxilb-io/octavia-loxilb-driver/blob/main/CHANGELOG.md
Keywords: openstack,octavia,loadbalancer,loxilb
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: OpenStack
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Networking
Requires-Python: <3.13,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: alembic>=1.10
Requires-Dist: attrs>=22.0.0
Requires-Dist: cotyledon>=1.3.0
Requires-Dist: httpx>=0.24.0
Requires-Dist: keystoneauth1>=4.3.0
Requires-Dist: octavia-lib>=3.8.0
Requires-Dist: openstacksdk>=0.61.0
Requires-Dist: oslo.concurrency>=5.0.0
Requires-Dist: oslo.config>=8.0.0
Requires-Dist: oslo.db>=8.4.0
Requires-Dist: oslo.log>=4.4.0
Requires-Dist: oslo.messaging>=12.4.0
Requires-Dist: oslo.reports>=1.18.0
Requires-Dist: oslo.serialization>=4.1.0
Requires-Dist: oslo.utils>=4.8.0
Requires-Dist: pydantic>=2.6
Requires-Dist: python-barbicanclient>=5.1.0
Requires-Dist: python-dateutil>=2.8.0
Requires-Dist: python-neutronclient>=7.2.0
Requires-Dist: requests>=2.25.0
Requires-Dist: SQLAlchemy>=1.4.0
Requires-Dist: stevedore>=3.3.0
Requires-Dist: taskflow>=4.0.0
Requires-Dist: tenacity>=6.2.0
Requires-Dist: urllib3>=1.26.0
Provides-Extra: dev
Requires-Dist: bandit<2.0,>=1.8.0; extra == "dev"
Requires-Dist: fixtures>=3.0.0; extra == "dev"
Requires-Dist: hacking>=7.0.0; extra == "dev"
Requires-Dist: hypothesis>=6.0; extra == "dev"
Requires-Dist: mock>=4.0.0; extra == "dev"
Requires-Dist: mypy<2.2,>=2.1; extra == "dev"
Requires-Dist: pre-commit>=2.15.0; extra == "dev"
Requires-Dist: pytest>=6.0; extra == "dev"
Requires-Dist: pytest-cov>=2.0; extra == "dev"
Requires-Dist: pytest-mock>=3.6.0; extra == "dev"
Requires-Dist: ruff>=0.5.0; extra == "dev"
Requires-Dist: testtools>=2.4.0; extra == "dev"
Requires-Dist: types-python-dateutil; extra == "dev"
Provides-Extra: docs
Requires-Dist: openstackdocstheme>=2.4.0; extra == "docs"
Requires-Dist: sphinx>=4.0; extra == "docs"
Requires-Dist: sphinx-rtd-theme>=1.0; extra == "docs"
Requires-Dist: sphinxcontrib-programoutput>=0.17; extra == "docs"
Dynamic: license-file

# LoxiLB Octavia Provider Driver

[![PyPI version](https://badge.fury.io/py/octavia-loxilb-driver.svg)](https://pypi.org/project/octavia-loxilb-driver/)
[![Python 3.10+](https://img.shields.io/badge/python-3.10--3.12-blue.svg)](https://www.python.org/downloads/)
[![OpenStack 2025.1 / 2025.2](https://img.shields.io/badge/openstack-2025.1%20Epoxy%20%7C%202025.2%20Flamingo-red.svg)](https://docs.openstack.org/octavia/)
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

An OpenStack **Octavia provider driver** that uses [LoxiLB](https://github.com/loxilb-io/loxilb) — an eBPF/XDP-based load balancer — as the data plane for Octavia load balancers.

The driver implements the `octavia-lib` provider contract, translating Octavia
load-balancer / listener / pool / member / health-monitor operations into LoxiLB
REST API calls. It supports two deployment topologies and is validated against the
upstream `octavia-tempest-plugin` on OpenStack **2025.1 Epoxy** (with **2025.2
Flamingo** support).

---

## Features

- **eBPF/XDP data plane** — load balancing powered by LoxiLB.
- **Two deployment topologies**:
  - **`amphora_style`** — the driver provisions and manages a dedicated LoxiLB VM per
    load balancer (Nova-booted), mirroring the amphora model.
  - **`external`** — the driver programs an existing, operator-managed LoxiLB cluster
    via its REST API.
- **High availability** — `SINGLE`, `ACTIVE_STANDBY`, and `ACTIVE_ACTIVE` topologies;
  BFD-based failover for active/standby (amphora_style).
- **Load-balancing algorithms** — `ROUND_ROBIN`, weighted round-robin (member
  weights), `SOURCE_IP`, `SOURCE_IP_PORT`, and `LEAST_CONNECTIONS`.
- **Health monitors** — `HTTP`, `HTTPS`, `TCP`, `UDP_CONNECT`, and `PING` mapped to
  LoxiLB endpoint health probes.
- **Flexible VIP networking** — L2 (`l2_aap`) and BGP (`bgp`) VIP modes; selectable
  NAT mode (`SNAT` / `DNAT` / `FULLNAT` / `ONEARM`).
- **Split-process design** — a synchronous provider driver inside `octavia-api` plus
  an asynchronous `octavia-loxilb-controller-worker` for long-running provisioning.

---

## How it works

```
                      ┌───────────────────────────┐
 openstack            │        octavia-api        │
 loadbalancer  ─────▶ │   LoxiLBProviderDriver    │    (in-process provider driver)
 create ...           └────────────┬──────────────┘
                                   │  RPC cast (oslo.messaging, topic loxilb_octavia)
                                   ▼
                      ┌───────────────────────────┐
                      │ octavia-loxilb-controller │   (cotyledon service, TaskFlow)
                      │         -worker           │
                      └────────────┬──────────────┘
                                   │  LoxiLB REST API (/netlox/v1/..., :11111)
                                   ▼
        amphora_style: driver-managed LoxiLB VM(s)   │   external: existing
        booted per load balancer via Nova            │   LoxiLB cluster
```

Authoritative state lives in Octavia's database; LoxiLB owns runtime LB-service
state. The driver keeps an Octavia↔LoxiLB ID mapping (LoxiLB has no unique IDs for
sub-resources) persisted to `id_mapping_storage_path`.

---

## Requirements

| Component | Requirement |
|-----------|-------------|
| OpenStack | Octavia on **2025.1 Epoxy** (validated) or **2025.2 Flamingo** |
| Python | **3.10 – 3.12** |
| `octavia-lib` | `>= 3.8.0` |
| Services | Octavia **API + driver-agent**, Nova, Neutron, Keystone, Glance, a message bus (RabbitMQ), MySQL/MariaDB |
| LoxiLB | A reachable LoxiLB exposing `/netlox/v1/...` on `:11111` — either an external cluster (`external` mode) or the LoxiLB VM image registered in Glance (`amphora_style` mode) |

`octavia-driver-agent` must be running: the driver pushes provisioning and operating
status through the driver-agent's status socket (`octavia_lib`'s `DriverLibrary`), so
without it load balancers never leave `PENDING_CREATE`.

For the LoxiLB VM image (`amphora_style`), see **[docs/LOXILB-VM-IMAGES.md](docs/LOXILB-VM-IMAGES.md)**.

---

## Installation

Use [docs/INSTALL.md](docs/INSTALL.md) as the **authoritative operator runbook**.
The README section below is only a quick-start overview: `pip install` alone is
not enough to produce a working deployment.

At minimum, a real deployment must also:

1. apply the driver's database migrations,
2. configure `[api_settings]` and `[loxilb]`,
3. provide topology-specific resources and credentials for `amphora_style`,
4. install and start `octavia-loxilb-controller-worker`, and
5. restart `octavia-api` and verify that `loxilb` appears in `openstack loadbalancer provider list`.

Install the package into the **same Python environment that `octavia-api` and the
Octavia worker run from** (so the entry points are discoverable):

```bash
pip install octavia-loxilb-driver
```

> **Version note.** These instructions describe **1.1.0** (this repository). The latest
> release published to PyPI at the time of writing is **1.0.3**, which predates the
> `octavia-loxilb-db-manage` console script and the driver's database migrations. Check
> with `pip show octavia-loxilb-driver`; if you get anything older than 1.1.0, install
> from source instead:
>
> ```bash
> pip install "git+https://github.com/loxilb-io/octavia-loxilb-driver.git@main"
> ```

Containerized control planes (Kolla-Ansible, OpenStack-Helm, TripleO) must install
the package into the Octavia API/worker container images (or a persistent overlay),
not just a transient `docker exec`. Example for Kolla-Ansible:

```bash
sudo docker exec -u root octavia_api    /var/lib/kolla/venv/bin/pip install octavia-loxilb-driver
sudo docker exec -u root octavia_worker /var/lib/kolla/venv/bin/pip install octavia-loxilb-driver
```

The version note above applies here too — check `pip show octavia-loxilb-driver` inside
each container and fall back to the `git+https://...` install if it reports < 1.1.0.

### Console scripts

Installing the package provides three console scripts:

| Command | Purpose |
|---------|---------|
| `octavia-loxilb-setup` | Bootstrap/inspect OpenStack resources for the driver |
| `octavia-loxilb-controller-worker` | The asynchronous controller-worker service (run via systemd) |
| `octavia-loxilb-db-manage` | Apply the driver's database migrations |

---

## Configuration

### 1. Enable the provider in Octavia

In `/etc/octavia/octavia.conf`:

```ini
[api_settings]
enabled_provider_drivers = amphora:Amphora provider,loxilb:LoxiLB provider driver
```

> The LoxiLB driver runs **in-process** inside `octavia-api`; it does **not** require
> an entry in `enabled_provider_agents` (it ships no
> `octavia.driver_agent.provider_agents` entry point, so adding one makes
> `octavia-driver-agent` fail to load it). `octavia-driver-agent` itself **must still be
> running** — the driver reports status through its status socket.

### 2. Configure the `[loxilb]` section

```ini
[loxilb]
# --- Deployment topology ---
# amphora_style | external
deployment_topology = amphora_style
# l2_aap | bgp
vip_mode = l2_aap
# SNAT | DNAT | FULLNAT | ONEARM
nat_mode = FULLNAT
# SINGLE | ACTIVE_STANDBY | ACTIVE_ACTIVE
default_topology = SINGLE

# --- LoxiLB REST API ---
# Required for 'external' mode (comma-separated cluster endpoints). In
# 'amphora_style' the driver discovers the endpoint of each VM it boots.
api_endpoints = http://192.0.2.10:11111,http://192.0.2.11:11111
api_version = v6.0
api_timeout = 30
api_retries = 3
api_use_ssl = false
# none | password | token | tls  ('password' is the basic-auth value)
loxilb_auth_type = none

# --- Controller-worker RPC ---
rpc_topic = loxilb_octavia

# --- ID-mapping persistence (must be writable by the octavia user) ---
id_mapping_storage_path = /var/lib/octavia/loxilb_id_mappings.json

# --- amphora_style: driver-managed LoxiLB VM provisioning ---
image_id = <glance id of the LoxiLB VM image>
flavor_id = <nova flavor id>
network_id = <tenant/data network id>
mgmt_network_id = <octavia lb-mgmt-net id>
security_group_ids = <sg id>[,<sg id>...]
# optional: enables SSH into LoxiLB VMs
key_name = <nova keypair name>
use_mgmt_network = true
```

> **INI note:** oslo.config does **not** strip trailing `#` comments. `key = value  # note`
> is read as the literal value `value  # note`. Options with a fixed choice list
> (`deployment_topology`, `vip_mode`, `nat_mode`, `default_topology`, `loxilb_auth_type`)
> and typed options such as `api_use_ssl` abort startup with `ConfigFileValueError`;
> free-form options such as `key_name` silently take the polluted value. Keep comments on
> their own lines, as above.

### 3. Configure OpenStack identity (amphora_style)

`amphora_style` provisions Nova VMs and Neutron ports, so the driver needs an
OpenStack identity (Keystone). The runtime currently reads these values from the
`[loxilb]` group, so putting them only under `[service_auth]` is not sufficient
for driver-managed VM provisioning:

```ini
[loxilb]
auth_url = https://keystone.example.com:5000
auth_type = password
username = octavia
password = <octavia service password>
project_name = service
user_domain_name = Default
project_domain_name = Default
```

A complete, deployment-focused walkthrough is in [docs/INSTALL.md](docs/INSTALL.md).
A full sample config ships inside the installed package — print its path with the
Octavia venv's python:

```bash
python -c "import octavia_loxilb_driver, os; print(os.path.join(os.path.dirname(octavia_loxilb_driver.__file__), 'etc/octavia.conf.sample'))"
```

### 4. Apply migrations and start the controller-worker

Run these with the Octavia venv's `python` / console scripts:

```bash
octavia-loxilb-db-manage --config-file /etc/octavia/octavia.conf upgrade head

# the unit file ships inside the installed package - resolve it
UNIT=$(python -c "import octavia_loxilb_driver, os; print(os.path.join(os.path.dirname(octavia_loxilb_driver.__file__), 'install/octavia-loxilb-controller-worker.service'))")
sudo cp "$UNIT" /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now octavia-loxilb-controller-worker
sudo systemctl restart <your-octavia-api-service>
```

> The shipped unit is production-oriented: `User=octavia` and
> `ExecStart=/usr/local/bin/octavia-loxilb-controller-worker`. If you installed the driver
> into a venv (DevStack `/opt/stack/data/venv/bin`, Kolla `/var/lib/kolla/venv/bin`) or
> Octavia runs as a different user, the unit will fail to start until you override
> **both**. See
> [docs/INSTALL.md — DevStack override for the controller-worker unit](docs/INSTALL.md#devstack-override-for-the-controller-worker-unit).

See [docs/INSTALL.md](docs/INSTALL.md) for deployment-specific service names
(for example, DevStack vs. containerized control planes).

---

## Usage

This is a post-install smoke example, not the full operator deployment procedure.
It assumes the package is installed in the Octavia runtime venv, database
migrations are applied, `octavia-loxilb-controller-worker` is running, and, for
`amphora_style`, the image/network/security-group/auth settings are already
configured. For the full operator workflow, use [docs/INSTALL.md](docs/INSTALL.md).

Octavia locks the whole load-balancer tree while a provisioning operation is in flight,
so every mutating command below uses `--wait`. Without it the next command fails with
HTTP 409 `Load Balancer ... is immutable and cannot be updated`. In `amphora_style` the
first create boots a Nova VM, so it can take minutes.

```bash
# Confirm the provider is registered
openstack loadbalancer provider list        # 'loxilb' should be listed

# Create a load balancer backed by LoxiLB
LB_ID=$(openstack loadbalancer create --name web-lb \
  --vip-subnet-id <vip-subnet> --provider loxilb --wait -f value -c id)

# Listener -> pool -> members
openstack loadbalancer listener create --name l1 \
  --protocol TCP --protocol-port 80 --wait "$LB_ID"

POOL_ID=$(openstack loadbalancer pool create --name p1 \
  --lb-algorithm ROUND_ROBIN --protocol TCP --listener l1 --wait -f value -c id)

openstack loadbalancer member create --address 10.0.0.11 \
  --protocol-port 80 --subnet-id <member-subnet> --wait "$POOL_ID"
openstack loadbalancer member create --address 10.0.0.12 \
  --protocol-port 80 --subnet-id <member-subnet> --wait "$POOL_ID"

# Health monitor
openstack loadbalancer healthmonitor create --name hm1 \
  --type TCP --delay 5 --timeout 3 --max-retries 3 --wait "$POOL_ID"

openstack loadbalancer show "$LB_ID"

# Clean up the smoke resources when finished
openstack loadbalancer delete --cascade --wait "$LB_ID"
```

### Selecting topology per load balancer

Cloud-wide defaults come from `[loxilb]`. Per-load-balancer overrides (e.g.
`ACTIVE_STANDBY`, `vip_mode`) are set via an **Octavia flavor**:

```bash
openstack loadbalancer flavorprofile create --name loxilb-as \
  --provider loxilb --flavor-data '{"loadbalancer_topology": "ACTIVE_STANDBY"}'
openstack loadbalancer flavor create --name loxilb-active-standby \
  --flavorprofile loxilb-as --enable
openstack loadbalancer create --name ha-lb --provider loxilb \
  --flavor loxilb-active-standby --vip-subnet-id <vip-subnet> --wait
```

---

## Supported feature matrix

| Capability | Support |
|------------|---------|
| Protocols | TCP, UDP |
| Algorithms | `ROUND_ROBIN`, weighted RR, `SOURCE_IP`, `SOURCE_IP_PORT`, `LEAST_CONNECTIONS` |
| Health monitors | `HTTP`, `HTTPS`, `TCP`, `UDP_CONNECT`, `PING` |
| Topologies | `SINGLE`, `ACTIVE_STANDBY`, `ACTIVE_ACTIVE` |
| Deployment models | `amphora_style` (driver-managed VMs), `external` (existing cluster) |
| VIP modes | `l2_aap`, `bgp` |
| NAT modes | `SNAT`, `DNAT`, `FULLNAT`, `ONEARM` |

> **Roadmap:** TLS termination and L7 policies are planned for later releases
> (`v1.x` / `v2`). See the project roadmap for status.

---

## Troubleshooting

**Provider not listed by `openstack loadbalancer provider list`:**
the package must be installed in the *same* venv as `octavia-api`, and
`enabled_provider_drivers` must include `loxilb`. Restart `octavia-api` after changes.

**Load balancer stuck in `PENDING_CREATE`:**
check the controller-worker is running and bound to the RPC topic —
`sudo systemctl status octavia-loxilb-controller-worker` and
`sudo rabbitmqctl list_queues name consumers | grep loxilb_octavia` (consumers ≥ 1).

**Controller-worker fails at startup with DB / migration errors:**
run `octavia-loxilb-db-manage --config-file /etc/octavia/octavia.conf upgrade head`
and then inspect `sudo journalctl -u octavia-loxilb-controller-worker --no-pager`.

**Controller-worker cannot reach a LoxiLB VM (`amphora_style`):**
the worker runs in the host network and must have a route to the LoxiLB VM's
management NIC. Use a routable management network (a Flat/VLAN provider network is
recommended over a tenant overlay the host cannot reach). Verify with
`curl http://<loxilb-mgmt-ip>:11111/netlox/v1/config/loadbalancer/all`.

See **[docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)** for more.

---

## Documentation

| Document | Description |
|----------|-------------|
| [Installation Guide](docs/INSTALL.md) | Operator install/configure walkthrough |
| [VM Images Guide](docs/LOXILB-VM-IMAGES.md) | LoxiLB VM image distribution & registration |
| [Troubleshooting](docs/TROUBLESHOOTING.md) | Common issues and fixes |

---

## Contributing

Contributions are welcome.

```bash
git clone https://github.com/loxilb-io/octavia-loxilb-driver.git
cd octavia-loxilb-driver
pip install -e .
python -m pytest octavia_loxilb_driver/tests/unit/ -v
```

Please run `ruff format`, `ruff check`, and the relevant tests (or
`pre-commit run --all-files`) before submitting changes.

---

## Support

- **Issues:** https://github.com/loxilb-io/octavia-loxilb-driver/issues
- **LoxiLB:** https://github.com/loxilb-io/loxilb

## License

Apache License 2.0 — see [LICENSE](LICENSE).

---

*An OpenStack Octavia provider driver for LoxiLB, by the LoxiLB / NetLOX team and contributors.*
