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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ members = [
"controllers/pxe-intent",
"controllers/netbox",
"controllers/routeros",
"controllers/dhcp",
"crates/netbox-client",
"crates/routeros-client",
"crates/pxe-server",
Expand Down
80 changes: 80 additions & 0 deletions Tiltfile
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,86 @@ local_resource(
# Use Tilt UI to trigger verification manually, or it will run after controller starts
)

# ====================
# Kea DHCP Server
# ====================
# Deploy ISC Kea DHCP server with Control Agent
# Image is built and pushed by GitHub Actions in the Kea fork
# Available at:
# - docker.io/microscaler/kea-dhcp:latest (Docker Hub)
# - ghcr.io/microscaler/kea-dhcp:latest (GitHub Container Registry)
k8s_yaml(kustomize('%s/config/kea-dhcp' % DCops_DIR))

k8s_resource(
'kea-dhcp',
labels=['infrastructure'],
port_forwards=[
'8000:8000', # Kea Control Agent REST API: localhost:8000 -> pod:8000
],
)

# ====================
# DHCP Controller
# ====================
# Build the DHCP Controller binary
# Uses host_aware_build.py for cross-compilation (macOS -> Linux)
# Note: host_aware_build.py passes all args to cargo, so --release works
local_resource(
'build-dhcp-controller',
cmd='python3 scripts/host_aware_build.py --release -p dhcp-controller',
deps=[
'controllers/dhcp/src',
'controllers/dhcp/Cargo.toml',
'crates/crds/src',
'Cargo.toml',
'Cargo.lock',
'scripts/host_aware_build.py',
],
resource_deps=['generate-crds'], # Wait for CRDs to be generated and applied
labels=['controllers'],
allow_parallel=True,
)

# Build Docker image for DHCP Controller
# Use custom_build to ensure binary exists before Docker build
# This matches the pattern from netbox-controller
# Note: We build for linux/amd64 platform even on Apple Silicon
# because the binary is cross-compiled for x86_64-unknown-linux-musl
# The 'deps' parameter ensures the binary exists before Docker build
DHCP_BINARY_PATH = 'target/x86_64-unknown-linux-musl/release/dhcp-controller'
DHCP_IMAGE_NAME = 'dhcp-controller'
DHCP_FULL_IMAGE_NAME = '%s/%s' % (REGISTRY, DHCP_IMAGE_NAME)

custom_build(
DHCP_IMAGE_NAME,
'docker buildx build --platform linux/amd64 -f dockerfiles/Dockerfile.dhcp-controller.dev -t %s:tilt . && docker tag %s:tilt %s:tilt && docker push %s:tilt' % (
DHCP_IMAGE_NAME,
DHCP_IMAGE_NAME,
DHCP_FULL_IMAGE_NAME,
DHCP_FULL_IMAGE_NAME
),
deps=[
DHCP_BINARY_PATH, # File dependency ensures binary exists before Docker build
'dockerfiles/Dockerfile.dhcp-controller.dev',
],
tag='tilt',
live_update=[
sync(DHCP_BINARY_PATH, '/app/dhcp-controller'),
run('kill -HUP 1', trigger=[DHCP_BINARY_PATH]),
],
)

# Deploy DHCP Controller
# This includes: namespace, serviceaccount, role (RBAC), rolebinding, deployment
# RBAC permissions are automatically applied via kustomize
k8s_yaml(kustomize('%s/config/dhcp-controller' % DCops_DIR))

k8s_resource(
'dhcp-controller',
labels=['controllers'],
resource_deps=['build-dhcp-controller', 'kea-dhcp'], # Wait for binary and Kea to be ready
)

# ====================
# Future Controllers
# ====================
Expand Down
54 changes: 54 additions & 0 deletions config/dhcp-controller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# DHCP Controller Configuration

## Environment Variables

### `KEA_CONTROL_AGENT_URL`
The URL of the ISC Kea Control Agent REST API.

**Default**: `http://localhost:8000`

**Configuration Options**:
- **Same namespace**: `http://kea-dhcp.dcops-system:8000`
- **Different namespace**: `http://kea-dhcp.kea:8000` (if Kea is in `kea` namespace)
- **Port-forward (local dev)**: `http://localhost:8000` (requires `kubectl port-forward`)

**Note**: The controller will log warnings if Kea is unavailable but will continue running and retry on CRD changes.

### `WATCH_NAMESPACE`
The Kubernetes namespace to watch for NetBox CRDs.

**Default**: `default`

**Options**:
- Set to a specific namespace to watch only that namespace
- Leave unset or empty to watch all namespaces (requires ClusterRole)

## Kea Deployment

The DHCP controller requires an ISC Kea DHCP server with Control Agent enabled.

### Quick Start (for testing)

If Kea is not yet deployed, you can:

1. **Use port-forward for local testing**:
```bash
# If Kea is deployed elsewhere
kubectl port-forward -n kea svc/kea-dhcp 8000:8000
```
Then set `KEA_CONTROL_AGENT_URL=http://localhost:8000` in the deployment.

2. **Deploy Kea separately**:
- Deploy ISC Kea with Control Agent enabled
- Update `KEA_CONTROL_AGENT_URL` to point to the Kea service
- The controller will automatically connect when Kea becomes available

### Controller Behavior

The controller handles Kea unavailability gracefully:
- **Startup**: Logs a warning if Kea is unavailable, but continues running
- **Reconciliation**: Logs warnings on sync failures, but doesn't fail reconciliation
- **Retry**: Automatically retries when CRDs change or on periodic requeue

This allows the controller to start before Kea is deployed and automatically sync when Kea becomes available.

35 changes: 35 additions & 0 deletions config/dhcp-controller/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: dhcp-controller
namespace: dcops-system
labels:
app: dhcp-controller
spec:
replicas: 1
selector:
matchLabels:
app: dhcp-controller
template:
metadata:
labels:
app: dhcp-controller
spec:
serviceAccountName: dhcp-controller
containers:
- name: dhcp-controller
image: dhcp-controller
imagePullPolicy: Always
env:
- name: KEA_CONTROL_AGENT_URL
value: "http://kea-dhcp.dcops-system:8000" # Kea Control Agent URL (via Kubernetes service)
- name: WATCH_NAMESPACE
value: "default" # Watch specific namespace, or remove to watch all
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi

12 changes: 12 additions & 0 deletions config/dhcp-controller/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: dcops-system

resources:
# namespace.yaml is already defined in netbox-controller, so we don't include it here
- serviceaccount.yaml
- role.yaml
- rolebinding.yaml
- deployment.yaml

30 changes: 30 additions & 0 deletions config/dhcp-controller/role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: dhcp-controller
labels:
app: dhcp-controller
rules:
- apiGroups:
- dcops.microscaler.io
resources:
# DHCP controller needs read access to NetBox CRDs to build Kea config
- netboxprefixes
- netboxipranges
- netboxipaddresses
verbs:
- get
- list
- watch
- apiGroups:
- dcops.microscaler.io
resources:
# Status updates for DHCP-related CRDs (if needed in future)
- netboxprefixes/status
- netboxipranges/status
- netboxipaddresses/status
verbs:
- get
- update
- patch

15 changes: 15 additions & 0 deletions config/dhcp-controller/rolebinding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dhcp-controller
labels:
app: dhcp-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: dhcp-controller
subjects:
- kind: ServiceAccount
name: dhcp-controller
namespace: dcops-system

8 changes: 8 additions & 0 deletions config/dhcp-controller/serviceaccount.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: dhcp-controller
namespace: dcops-system
labels:
app: dhcp-controller

55 changes: 55 additions & 0 deletions config/kea-dhcp/configmap-postgres.yaml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: kea-dhcp-config-postgres
namespace: dcops-system
labels:
app: kea-dhcp
data:
kea-dhcp4.conf: |
{
"Dhcp4": {
"interfaces-config": {
"interfaces": ["*"]
},
"control-socket": {
"socket-type": "http",
"socket-name": "/tmp/kea-http-socket",
"socket-url": "http://127.0.0.1:8000"
},
"lease-database": {
"type": "postgresql",
"name": "kea",
"host": "postgresql.dcops-system.svc.cluster.local",
"port": 5432,
"user": "kea",
"password": "kea-password",
"lfc-interval": 3600
},
"subnet4": [],
"loggers": [
{
"name": "kea-dhcp4",
"output_options": [
{
"output": "stdout"
}
],
"severity": "INFO",
"debuglevel": 0
}
]
},
"Control-agent": {
"http-host": "0.0.0.0",
"http-port": 8000,
"control-sockets": {
"dhcp4": {
"socket-type": "http",
"socket-name": "/tmp/kea-http-socket",
"socket-url": "http://127.0.0.1:8000"
}
}
}
}

60 changes: 60 additions & 0 deletions config/kea-dhcp/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: kea-dhcp-config
namespace: dcops-system
labels:
app: kea-dhcp
data:
kea-dhcp4.conf: |
{
"Dhcp4": {
"interfaces-config": {
"interfaces": ["*"]
},
"control-socket": {
"socket-type": "http",
"socket-name": "/tmp/kea-http-socket",
"socket-url": "http://127.0.0.1:8000"
},
"lease-database": {
"type": "memfile",
"lfc-interval": 3600
},
# Alternative PostgreSQL configuration (uncomment to use):
# "lease-database": {
# "type": "postgresql",
# "name": "kea",
# "host": "postgresql.dcops-system.svc.cluster.local",
# "port": 5432,
# "user": "kea",
# "password": "kea-password",
# "lfc-interval": 3600
# },
"subnet4": [],
"loggers": [
{
"name": "kea-dhcp4",
"output_options": [
{
"output": "stdout"
}
],
"severity": "INFO",
"debuglevel": 0
}
]
},
"Control-agent": {
"http-host": "0.0.0.0",
"http-port": 8000,
"control-sockets": {
"dhcp4": {
"socket-type": "http",
"socket-name": "/tmp/kea-http-socket",
"socket-url": "http://127.0.0.1:8000"
}
}
}
}

Loading
Loading