https://github.com/openshift-hyperfleet/adapter-landing-zone
Handles environment preparation and prerequisite setup for GCP-based cluster provisioning operations.
https://github.com/openshift-hyperfleet/adapter-landing-zone
Last synced: 5 months ago
JSON representation
Handles environment preparation and prerequisite setup for GCP-based cluster provisioning operations.
- Host: GitHub
- URL: https://github.com/openshift-hyperfleet/adapter-landing-zone
- Owner: openshift-hyperfleet
- License: apache-2.0
- Created: 2025-12-10T07:50:37.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-12-30T02:36:48.000Z (6 months ago)
- Last Synced: 2026-01-02T11:54:26.452Z (5 months ago)
- Language: Shell
- Size: 35.2 KB
- Stars: 0
- Watchers: 0
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# HyperFleet Landing Zone Adapter
Event-driven adapter for HyperFleet cluster provisioning. Handles environment preparation and prerequisite setup for GCP-based cluster provisioning operations. Consumes CloudEvents from message brokers (GCP Pub/Sub, RabbitMQ), processes AdapterConfig, manages Kubernetes resources, and reports status via API.
## Table of Contents
- [Prerequisites](#prerequisites)
- [Local Development](#local-development)
- [GCP Authentication](#gcp-authentication)
- [Helm Chart Installation](#helm-chart-installation)
- [Configuration](#configuration)
- [Examples](#examples)
- [GCP Workload Identity Setup](#gcp-workload-identity-setup)
- [Notes](#notes)
## Prerequisites
- Kubernetes 1.19+
- Helm 3.0+
- GCP Workload Identity (for Pub/Sub access)
- `gcloud` CLI configured with appropriate permissions
## Local Development
Run the adapter locally for development and testing.
### Prerequisites
- `hyperfleet-adapter` binary installed and in PATH
- GCP service account key for Pub/Sub access (see [GCP Authentication](#gcp-authentication))
- Access to a GKE cluster (for applying Kubernetes resources)
- `podman` or `docker` for RabbitMQ (if `BROKER_TYPE=rabbitmq`)
### Setup
1. Copy environment template:
```bash
cp env.example .env
```
2. Edit `.env` with your configuration:
```bash
# Required for Google Pub/Sub (default)
GCP_PROJECT_ID="your-gcp-project-id"
BROKER_TOPIC="hyperfleet-adapter-topic"
BROKER_SUBSCRIPTION_ID="hyperfleet-adapter-landing-zone-subscription"
# Required for all broker types
HYPERFLEET_API_BASE_URL="https://localhost:8000"
# Optional (defaults provided)
SUBSCRIBER_PARALLELISM="1"
HYPERFLEET_API_VERSION="v1"
# Required for RabbitMQ (if BROKER_TYPE=rabbitmq)
# RABBITMQ_URL="amqp://guest:guest@localhost:5672/"
```
3. Set up GCP authentication (see [GCP Authentication](#gcp-authentication) for detailed steps):
```bash
# Create service account key and set in .env
export GOOGLE_APPLICATION_CREDENTIALS="./sa-key.json"
```
4. Connect to your GKE cluster (required for the adapter to apply Kubernetes resources):
```bash
# Get credentials for your GKE cluster (using variables from .env)
gcloud container clusters get-credentials "$GKE_CLUSTER_NAME" \
--region "$GKE_CLUSTER_REGION" \
--project "$GCP_PROJECT_ID"
# Verify connection
kubectl cluster-info
```
### Run
```bash
# For Google Pub/Sub (default)
make run-local
# For RabbitMQ
BROKER_TYPE=rabbitmq make run-local
# For RabbitMQ with Docker (override default podman)
BROKER_TYPE=rabbitmq CONTAINER_RUNTIME=docker make run-local
```
The script will:
- Auto-source `.env` if it exists
- Verify `hyperfleet-adapter` is installed
- Validate required environment variables
- **Auto-create Pub/Sub topic and subscription if missing** (for `googlepubsub` type)
- **Manage RabbitMQ container** (start/create for `rabbitmq` type)
- Generate broker config from `configs/broker-local-pubsub.yaml` or `configs/broker-local-rabbitmq.yaml`
- Start the adapter with verbose logging
### Local Environment Variables
| Variable | Required | Description | Default |
|----------|----------|-------------|---------|
| `GCP_PROJECT_ID` | Yes* | GCP project ID | - |
| `GKE_CLUSTER_NAME` | Yes | GKE cluster name for kubeconfig | - |
| `GKE_CLUSTER_REGION` | Yes | GKE cluster region (or use `GKE_CLUSTER_ZONE`) | - |
| `BROKER_TOPIC` | Yes* | Pub/Sub topic name | - |
| `BROKER_SUBSCRIPTION_ID` | Yes* | Pub/Sub subscription ID | - |
| `HYPERFLEET_API_BASE_URL` | Yes | HyperFleet API base URL | - |
| `SUBSCRIBER_PARALLELISM` | No | Number of parallel workers | `1` |
| `HYPERFLEET_API_VERSION` | No | API version | `v1` |
| `GOOGLE_APPLICATION_CREDENTIALS` | Yes* | Path to service account key file (recommended) | - |
| `RABBITMQ_URL` | No** | RabbitMQ connection URL (when using RabbitMQ broker) | `amqp://guest:guest@localhost:5672/` |
| `BROKER_TYPE` | No | Broker type: `googlepubsub` or `rabbitmq` | `googlepubsub` |
| `CONTAINER_RUNTIME` | No | Container runtime for RabbitMQ | `podman` |
\* Required when using GCP Pub/Sub broker (default)
\*\* Required when using RabbitMQ broker
### GCP Authentication
The adapter uses GCP Application Default Credentials (ADC). **Recommended:** Use a service account key file to avoid conflicts with other applications.
```bash
# 1. Create service account
gcloud iam service-accounts create hyperfleet-adapter-local \
--project="$GCP_PROJECT_ID" \
--display-name="HyperFleet Adapter Local Dev"
# 2. Grant Pub/Sub permissions
gcloud projects add-iam-policy-binding "$GCP_PROJECT_ID" \
--member="serviceAccount:hyperfleet-adapter-local@${GCP_PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/pubsub.subscriber"
# 3. Create key file
gcloud iam service-accounts keys create ./sa-key.json \
--iam-account="hyperfleet-adapter-local@${GCP_PROJECT_ID}.iam.gserviceaccount.com"
# 4. Add to .env
export GOOGLE_APPLICATION_CREDENTIALS="./sa-key.json"
```
> ⚠️ **Warning:** Do NOT use `gcloud auth application-default login` - it will override your default credentials and may block other applications using ADC from a different project.
## Helm Chart Installation
### Installing the Chart
```bash
helm install landing-zone ./charts/
```
### Install to a Specific Namespace
```bash
helm install landing-zone ./charts/ \
--namespace hyperfleet-system \
--create-namespace
```
### Uninstalling the Chart
```bash
helm delete landing-zone
# Or with namespace
helm delete landing-zone --namespace hyperfleet-system
```
## Configuration
All configurable parameters are in `values.yaml`. For advanced customization, modify the templates directly.
### Image & Replica
| Parameter | Description | Default |
|-----------|-------------|---------|
| `replicaCount` | Number of replicas | `1` |
| `image.registry` | Image registry | `quay.io/openshift-hyperfleet` |
| `image.repository` | Image repository | `hyperfleet-adapter` |
| `image.tag` | Image tag | `latest` |
| `image.pullPolicy` | Image pull policy | `Always` |
| `imagePullSecrets` | Image pull secrets | `[]` |
### Naming
| Parameter | Description | Default |
|-----------|-------------|---------|
| `nameOverride` | Override chart name | `""` |
| `fullnameOverride` | Override full release name | `""` |
### ServiceAccount & RBAC
| Parameter | Description | Default |
|-----------|-------------|---------|
| `serviceAccount.create` | Create ServiceAccount | `true` |
| `serviceAccount.name` | ServiceAccount name (auto-generated if empty) | `""` |
| `serviceAccount.annotations` | ServiceAccount annotations (for Workload Identity) | `{}` |
| `rbac.create` | Create ClusterRole and ClusterRoleBinding | `false` |
| `rbac.namespaceAdmin` | Grant namespace admin permissions | `false` |
When `rbac.namespaceAdmin=true`, the adapter gets full access to:
- Namespaces (create, update, delete)
- Core resources (configmaps, secrets, serviceaccounts, services, pods, PVCs)
- Apps (deployments, statefulsets, daemonsets, replicasets)
- Batch (jobs, cronjobs)
- Networking (ingresses, networkpolicies)
- RBAC (roles, rolebindings)
### Logging
| Parameter | Description | Default |
|-----------|-------------|---------|
| `logging.level` | Log level (`debug`, `info`, `warn`, `error`) | `info` |
| `logging.format` | Log format (`text`, `json`) | `text` |
| `logging.output` | Log output (`stdout`, `stderr`) | `stderr` |
### Scheduling
| Parameter | Description | Default |
|-----------|-------------|---------|
| `nodeSelector` | Node selector | `{}` |
| `tolerations` | Tolerations | `[]` |
| `affinity` | Affinity rules | `{}` |
### Adapter Configuration
The adapter config is always created from `charts/configs/adapter-landing-zone.yaml`:
- Mounted at `/etc/adapter/adapter.yaml`
- Exposed via `ADAPTER_CONFIG_PATH` environment variable
To customize, edit `charts/configs/adapter-landing-zone.yaml` directly.
### Broker Configuration
The broker configuration generates a `broker.yaml` file that is mounted as a ConfigMap.
#### General Settings
| Parameter | Description | Default |
|-----------|-------------|---------|
| `broker.type` | Broker type: `googlepubsub` or `rabbitmq` (**required**) | `""` |
| `broker.subscriber.parallelism` | Number of parallel workers | `1` |
| `broker.yaml` | Raw YAML override (advanced use) | `""` |
#### Google Pub/Sub (when `broker.type=googlepubsub`)
| Parameter | Description | Default |
|-----------|-------------|---------|
| `broker.googlepubsub.projectId` | GCP project ID (**required**) | `""` |
| `broker.googlepubsub.topic` | Pub/Sub topic name (**required**) | `""` |
| `broker.googlepubsub.subscription` | Pub/Sub subscription ID (**required**) | `""` |
| `broker.googlepubsub.deadLetterTopic` | Dead letter topic name (optional) | `""` |
Other Pub/Sub settings (ack deadline, retention, goroutines, etc.) are configured with sensible defaults in the broker config template.
#### RabbitMQ (when `broker.type=rabbitmq`)
| Parameter | Description | Default |
|-----------|-------------|---------|
| `broker.rabbitmq.url` | RabbitMQ connection URL (**required**) | `""` |
> **Note:** The `broker.rabbitmq.url` must be provided via `--set` or values file. Do not commit credentials to version control.
> Format: `amqp://username:password@hostname:port/vhost`
Other RabbitMQ settings (exchange type, prefetch count, etc.) are configured with sensible defaults in the broker config template.
When `broker.type` is set:
- Generates `broker.yaml` from structured values
- Creates ConfigMap with `broker.yaml` key
- Mounts at `/etc/broker/broker.yaml`
- Sets `BROKER_CONFIG_FILE=/etc/broker/broker.yaml`
### HyperFleet API
| Parameter | Description | Default |
|-----------|-------------|---------|
| `hyperfleetApi.baseUrl` | HyperFleet API base URL | `""` |
| `hyperfleetApi.version` | API version | `v1` |
### Environment Variables
| Parameter | Description | Default |
|-----------|-------------|---------|
| `env` | Additional environment variables | `[]` |
Example:
```yaml
env:
- name: MY_VAR
value: "my-value"
- name: MY_SECRET
valueFrom:
secretKeyRef:
name: my-secret
key: key
```
## Examples
### Basic Installation with Google Pub/Sub
```bash
helm install landing-zone ./charts/ \
--set broker.type=googlepubsub \
--set broker.googlepubsub.projectId=my-gcp-project \
--set broker.googlepubsub.topic=my-topic \
--set broker.googlepubsub.subscription=my-subscription
```
### With HyperFleet API Configuration
```bash
helm install landing-zone ./charts/ \
--set hyperfleetApi.baseUrl=https://api.hyperfleet.example.com \
--set broker.type=googlepubsub \
--set broker.googlepubsub.projectId=my-gcp-project \
--set broker.googlepubsub.topic=my-topic \
--set broker.googlepubsub.subscription=my-subscription
```
### With RabbitMQ
```bash
helm install landing-zone ./charts/ \
--set broker.type=rabbitmq \
--set broker.rabbitmq.url="amqp://user:password@rabbitmq.svc:5672/"
```
> **Security:** For production, store credentials in a Kubernetes Secret and reference via `env`.
### With GCP Workload Identity and RBAC
First, grant Pub/Sub permissions to the KSA (before deploying):
```bash
# Get project number
gcloud projects describe my-gcp-project --format="value(projectNumber)"
# Grant permissions using direct principal binding (no GSA needed)
gcloud projects add-iam-policy-binding my-gcp-project \
--role="roles/pubsub.subscriber" \
--member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/my-gcp-project.svc.id.goog/subject/ns/hyperfleet-system/sa/landing-zone"
```
Then deploy:
```bash
helm install landing-zone ./charts/ \
--namespace hyperfleet-system \
--create-namespace \
--set image.registry=us-central1-docker.pkg.dev/my-project/my-repo \
--set image.repository=hyperfleet-adapter \
--set image.tag=v0.1.0 \
--set broker.type=googlepubsub \
--set broker.googlepubsub.projectId=my-gcp-project \
--set broker.googlepubsub.topic=my-topic \
--set broker.googlepubsub.subscription=my-subscription \
--set hyperfleetApi.baseUrl=https://api.hyperfleet.example.com \
--set rbac.create=true \
--set rbac.namespaceAdmin=true
```
### With Custom Logging
```bash
helm install landing-zone ./charts/ \
--set logging.level=debug \
--set logging.format=json \
--set logging.output=stdout \
--set broker.type=googlepubsub \
--set broker.googlepubsub.projectId=my-gcp-project \
--set broker.googlepubsub.topic=my-topic \
--set broker.googlepubsub.subscription=my-subscription
```
### Using Existing ServiceAccount
```bash
helm install landing-zone ./charts/ \
--set serviceAccount.create=false \
--set serviceAccount.name=my-existing-sa
```
### With Values File
Example my-values.yaml
```yaml
replicaCount: 2
image:
registry: us-central1-docker.pkg.dev/my-project/my-repo
repository: hyperfleet-adapter
tag: v0.1.0
serviceAccount:
create: true
annotations:
iam.gke.io/gcp-service-account: adapter@my-project.iam.gserviceaccount.com
rbac:
create: true
namespaceAdmin: true
logging:
level: debug
format: json
output: stderr
hyperfleetApi:
baseUrl: https://api.hyperfleet.example.com
version: v1
broker:
type: googlepubsub
googlepubsub:
projectId: my-gcp-project
topic: hyperfleet-events
subscription: hyperfleet-adapter-subscription
subscriber:
parallelism: 10
```
Install with values file:
```bash
helm install landing-zone ./charts/ -f my-values.yaml
```
## Deployment Environment Variables
The deployment sets these environment variables automatically:
| Variable | Value | Condition |
|----------|-------|-----------|
| `HYPERFLEET_API_BASE_URL` | From `hyperfleetApi.baseUrl` | When set |
| `HYPERFLEET_API_VERSION` | From `hyperfleetApi.version` | Always (default: v1) |
| `ADAPTER_CONFIG_PATH` | `/etc/adapter/adapter.yaml` | Always |
| `BROKER_CONFIG_FILE` | `/etc/broker/broker.yaml` | When `broker.type` is set |
| `BROKER_SUBSCRIPTION_ID` | From `broker.googlepubsub.subscription` | When `broker.type=googlepubsub` |
| `BROKER_TOPIC` | From `broker.googlepubsub.topic` | When `broker.type=googlepubsub` |
| `GCP_PROJECT_ID` | From `broker.googlepubsub.projectId` | When `broker.type=googlepubsub` |
## GCP Workload Identity Setup
Grant GCP Pub/Sub permissions to the Kubernetes Service Account using **Workload Identity Federation**.
### Step 1: Get Project Number
```bash
gcloud projects describe MY_PROJECT --format="value(projectNumber)"
```
### Step 2: Grant Pub/Sub Permissions to KSA (Direct Principal Binding)
Run this **before** deploying so the pod works immediately:
```bash
# Grant subscriber permission
gcloud projects add-iam-policy-binding MY_PROJECT \
--role="roles/pubsub.subscriber" \
--member="principal://iam.googleapis.com/projects/MY_PROJECT_NUMBER/locations/global/workloadIdentityPools/MY_PROJECT.svc.id.goog/subject/ns/MY_NAMESPACE/sa/landing-zone" \
--condition=None
# Grant viewer permission (required to read subscription metadata)
gcloud projects add-iam-policy-binding MY_PROJECT \
--role="roles/pubsub.viewer" \
--member="principal://iam.googleapis.com/projects/MY_PROJECT_NUMBER/locations/global/workloadIdentityPools/MY_PROJECT.svc.id.goog/subject/ns/MY_NAMESPACE/sa/landing-zone" \
--condition=None
```
> **Note:** This uses direct principal binding - no Google Service Account (GSA) required. The binding works even before the KSA exists.
### Step 3: Wait for IAM Propagation
IAM changes can take 1-2 minutes to propagate. Wait until permissions are active:
```bash
# Wait until permissions are propagated
echo "Waiting for IAM propagation..."
while ! gcloud pubsub subscriptions describe MY_SUBSCRIPTION \
--project=MY_PROJECT &>/dev/null; do
echo " Waiting for permissions to propagate..."
sleep 10
done
echo "Permissions propagated!"
```
### Step 4: Deploy
```bash
helm install landing-zone ./charts/ \
--namespace MY_NAMESPACE \
--create-namespace \
--set broker.type=googlepubsub \
--set broker.googlepubsub.projectId=MY_PROJECT \
--set broker.googlepubsub.topic=MY_TOPIC \
--set broker.googlepubsub.subscription=MY_SUBSCRIPTION \
--set rbac.create=true \
--set rbac.namespaceAdmin=true
```
> **Note:** Replace the following placeholders:
> - `MY_PROJECT` - Your GCP project ID
> - `MY_PROJECT_NUMBER` - Your GCP project number (from Step 1)
> - `MY_NAMESPACE` - Kubernetes namespace (e.g., `hyperfleet-system`)
> - `MY_TOPIC` - Pub/Sub topic name
> - `MY_SUBSCRIPTION` - Pub/Sub subscription name
> - `landing-zone` - The Helm release name (KSA name)
### Step 5: Verify Workload Identity
```bash
# Test authentication from pod
kubectl run -it --rm debug \
--image=google/cloud-sdk:slim \
--serviceaccount=landing-zone \
--namespace=MY_NAMESPACE \
-- gcloud auth list
```
## Notes
- The adapter runs as non-root user (UID 65532) with read-only filesystem
- Health probes are disabled by default (adapter is a message consumer, not HTTP server)
- Uses `distroless` base image for minimal attack surface
- Config checksum annotation triggers pod restart on ConfigMap changes
- Default resource limits: 500m CPU, 512Mi memory
- Default resource requests: 100m CPU, 128Mi memory
## License
See [LICENSE](LICENSE) for details.