Skip to content

Commit 63ab6cb

Browse files
committed
test proxy
1 parent c8eec53 commit 63ab6cb

9 files changed

Lines changed: 2576 additions & 0 deletions

File tree

docs/PROXY_INTEGRATION.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# AMQP Proxy Sidecar Integration
2+
3+
## Overview
4+
5+
The RabbitMQ controller now automatically deploys an AMQP durability proxy as a sidecar container during upgrades and queue type migrations. This proxy enables seamless migration from classic/mirrored queues to quorum queues without requiring immediate OpenStack dataplane reconfiguration.
6+
7+
## Problem Solved
8+
9+
When migrating from RabbitMQ 3.9 (mirrored queues) to 4.2 (quorum queues), external OpenStack services have `amqp_durable_queues=false` configured. However, quorum queues require `durable=True`, causing `PRECONDITION_FAILED` errors. The proxy transparently rewrites AMQP frames to force durability, allowing non-durable clients to work with durable quorum queues.
10+
11+
## Architecture
12+
13+
```
14+
┌─────────────────────────────────────────┐
15+
│ RabbitMQ Pod │
16+
│ │
17+
│ ┌───────────────────┐ │
18+
│ │ amqp-proxy │ Port: 5672 │
19+
│ │ (with TLS) │ (external) │
20+
│ └─────────┬─────────┘ │
21+
│ │ localhost:5673 │
22+
│ ↓ (no TLS) │
23+
│ ┌───────────────────┐ │
24+
│ │ rabbitmq │ Port: 5673 │
25+
│ │ │ (localhost) │
26+
│ └───────────────────┘ │
27+
└─────────────────────────────────────────┘
28+
↑ Port 5672 (TLS)
29+
30+
External clients
31+
```
32+
33+
## How It Works
34+
35+
1. **Automatic Activation**: Proxy sidecar is automatically added when:
36+
- Upgrade is in progress (`Status.UpgradePhase != ""`)
37+
- Migrating to quorum queues before dataplane is reconfigured
38+
- Annotation `rabbitmq.openstack.org/enable-proxy=true` is set
39+
40+
2. **TLS Handling**:
41+
- Proxy terminates TLS on port 5672 (using certs from `Spec.TLS.SecretName`)
42+
- RabbitMQ listens on localhost:5673 without TLS
43+
- External clients connect to proxy with TLS
44+
45+
3. **Frame Rewriting**: Proxy intercepts AMQP frames and:
46+
- Rewrites `queue.declare(durable=False)``durable=True` + `x-queue-type=quorum`
47+
- Rewrites `exchange.declare(durable=False)``durable=True`
48+
- Skips reply queues and system queues
49+
50+
4. **Automatic Removal**: Proxy is removed after:
51+
- Dataplane is reconfigured with `amqp_durable_queues=true`
52+
- User sets annotation `rabbitmq.openstack.org/clients-reconfigured=true`
53+
54+
## Files Created/Modified
55+
56+
### New Files
57+
- `internal/controller/rabbitmq/proxy.go` - Proxy sidecar integration logic
58+
- `internal/controller/rabbitmq/data/proxy.py` - AMQP proxy script (embedded)
59+
- `internal/controller/rabbitmq/data/README.md` - Documentation for data files
60+
- `PROXY_INTEGRATION.md` - Complete integration documentation
61+
62+
### Modified Files
63+
- `internal/controller/rabbitmq/rabbitmq_controller.go` (lines 805-835):
64+
- Added proxy sidecar logic after `ConfigureCluster`
65+
- Calls `ensureProxyConfigMap`, `addProxySidecar`, `configureRabbitMQBackendPort`
66+
- Removes proxy when `shouldEnableProxy()` returns false
67+
68+
## Key Functions
69+
70+
### proxy.go
71+
72+
- `ensureProxyConfigMap(ctx, instance, helper)` - Creates ConfigMap with embedded proxy script
73+
- `addProxySidecar(instance, cluster)` - Adds proxy container to StatefulSet
74+
- `buildProxySidecarContainer(instance)` - Builds container spec with TLS support
75+
- `removeProxySidecar(cluster)` - Removes proxy sidecar
76+
- `shouldEnableProxy(instance)` - Determines when proxy should be enabled
77+
- `configureRabbitMQBackendPort(instance, cluster)` - Configures RabbitMQ to listen on localhost:5673
78+
79+
## Container Spec
80+
81+
- **Image**: `quay.io/openstack-k8s-operators/openstack-operator-client:latest`
82+
- **Command**: `python3 /scripts/proxy.py`
83+
- **Args**:
84+
- `--backend localhost:5673`
85+
- `--listen 0.0.0.0:5672`
86+
- `--tls-cert /etc/rabbitmq-tls/tls.crt` (if TLS enabled)
87+
- `--tls-key /etc/rabbitmq-tls/tls.key` (if TLS enabled)
88+
- `--tls-ca /etc/rabbitmq-tls-ca/ca.crt` (if CA specified)
89+
- **Resources**:
90+
- Requests: 128Mi memory, 100m CPU
91+
- Limits: 256Mi memory, 500m CPU
92+
- **Probes**: TCP liveness and readiness on port 5672
93+
94+
## Usage
95+
96+
### Automatic (during upgrade)
97+
98+
The proxy is automatically enabled when upgrading RabbitMQ:
99+
100+
```yaml
101+
apiVersion: rabbitmq.openstack.org/v1beta1
102+
kind: RabbitMq
103+
metadata:
104+
name: rabbitmq
105+
annotations:
106+
rabbitmq.openstack.org/target-version: "4.2.0"
107+
spec:
108+
queueType: Quorum
109+
tls:
110+
secretName: rabbitmq-tls
111+
```
112+
113+
### Manual activation
114+
115+
Force proxy activation with annotation:
116+
117+
```bash
118+
kubectl annotate rabbitmq rabbitmq \
119+
rabbitmq.openstack.org/enable-proxy=true
120+
```
121+
122+
### Manual deactivation
123+
124+
After dataplane reconfiguration:
125+
126+
```bash
127+
kubectl annotate rabbitmq rabbitmq \
128+
rabbitmq.openstack.org/clients-reconfigured=true
129+
```
130+
131+
## Monitoring
132+
133+
Check proxy logs:
134+
```bash
135+
kubectl logs rabbitmq-server-0 -c amqp-proxy
136+
```
137+
138+
Proxy prints statistics every 5 minutes:
139+
```
140+
=== Proxy Statistics ===
141+
Total connections: 25
142+
Queue rewrites: 120
143+
Exchange rewrites: 15
144+
Bytes forwarded: 5,432,100
145+
```
146+
147+
## Upgrade Workflow
148+
149+
1. **Start upgrade**: Set target-version annotation → Proxy enabled
150+
2. **Cluster recreated**: RabbitMQ 4.2 with quorum queues + proxy sidecar
151+
3. **External services**: Continue using `amqp_durable_queues=false`
152+
4. **Proxy rewrites**: Frames rewritten to use durable queues
153+
5. **Dataplane reconfig**: Update services to `amqp_durable_queues=true`
154+
6. **Set annotation**: `clients-reconfigured=true` → Proxy removed
155+
7. **Direct connection**: Services connect directly to RabbitMQ
156+
157+
## Important Notes
158+
159+
### Proxy Script Location
160+
161+
The proxy script is located at:
162+
- `internal/controller/rabbitmq/data/proxy.py`
163+
164+
When updating the proxy:
165+
1. Edit `internal/controller/rabbitmq/data/proxy.py`
166+
2. Rebuild: `make`
167+
3. Test: `make test`
168+
169+
### Performance
170+
171+
- Proxy adds ~0.05ms latency (localhost forwarding)
172+
- Memory overhead: ~64Mi per RabbitMQ pod
173+
- CPU overhead: ~20m per RabbitMQ pod
174+
175+
### Security
176+
177+
- Runs as non-root
178+
- No privilege escalation
179+
- Drops all capabilities
180+
- TLS certificates mounted read-only
181+
182+
## Testing
183+
184+
### Go Unit Tests
185+
186+
Proxy sidecar integration tests verify:
187+
- ✅ Proxy is added during upgrades
188+
- ✅ TLS configuration is correct
189+
- ✅ Proxy is removed after client reconfiguration
190+
- ✅ Manual activation via annotations
191+
192+
Run tests:
193+
```bash
194+
make test
195+
# Test Suite Passed
196+
# composite coverage: 72.7% of statements
197+
198+
# Run only proxy tests
199+
cd test/functional
200+
ginkgo -focus="RabbitMQ Proxy"
201+
```
202+
203+
### Python Integration Test
204+
205+
Simulates Oslo messaging client with `amqp_durable_queues=false` connecting through proxy to RabbitMQ with quorum queues.
206+
207+
Quick test:
208+
```bash
209+
cd internal/controller/rabbitmq/data
210+
python3 proxy_test.py --host localhost --port 5672
211+
```
212+
213+
For complete testing documentation, see [TESTING.md](internal/controller/rabbitmq/data/TESTING.md).
214+
215+
## References
216+
217+
- Proxy implementation: `internal/controller/rabbitmq/data/proxy.py`
218+
- Proxy integration: `internal/controller/rabbitmq/proxy.go`
219+
- AMQP 0-9-1 spec: https://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# RabbitMQ Controller Data Files
2+
3+
This directory contains embedded data files used by the RabbitMQ controller.
4+
5+
## Files
6+
7+
### proxy.py
8+
9+
The AMQP durability proxy script that is deployed as a sidecar container during RabbitMQ upgrades and queue type migrations.
10+
11+
**Purpose**: Transparently rewrites AMQP frames to force `durable=True`, enabling non-durable clients (OpenStack services with `amqp_durable_queues=false`) to work with durable quorum queues.
12+
13+
**Deployment**: Embedded at build time using Go's `embed` directive in `proxy.go` and deployed as a ConfigMap to RabbitMQ pods.
14+
15+
**Usage**: See [PROXY_INTEGRATION.md](../../../PROXY_INTEGRATION.md) for complete documentation.
16+
17+
### proxy_test.py
18+
19+
Integration test that simulates an Oslo messaging client (with `amqp_durable_queues=false`) connecting through the proxy to RabbitMQ with quorum queues.
20+
21+
**Usage**: See [TESTING.md](TESTING.md) for how to run the tests.
22+
23+
## Modifying the Proxy
24+
25+
When updating the proxy script:
26+
27+
1. Edit `internal/controller/rabbitmq/data/proxy.py`
28+
2. Rebuild the operator: `make`
29+
3. Run tests: `make test`
30+
4. Run integration test: `python3 proxy_test.py` (see [TESTING.md](TESTING.md))
31+
32+
The proxy is embedded at compile time, so changes require a rebuild.

0 commit comments

Comments
 (0)