Skip to content
Merged
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
16 changes: 8 additions & 8 deletions charts/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,16 @@ spec:
value: {{ .Values.auth.enableJwt | quote }}
- name: ENABLE_AUTHZ
value: {{ .Values.auth.enableAuthz | quote }}
{{- if .Values.adapters }}
{{- if .Values.adapters.cluster }}
- name: HYPERFLEET_CLUSTER_ADAPTERS
value: {{ .Values.adapters.cluster | toJson | quote }}
{{- end }}
{{- if .Values.adapters.nodepool }}
- name: HYPERFLEET_NODEPOOL_ADAPTERS
value: {{ .Values.adapters.nodepool | toJson | quote }}
{{- if not (and .Values.adapters (hasKey .Values.adapters "cluster")) }}
{{- fail "adapters.cluster is required - specify which adapters must be ready for clusters (e.g., [\"validation\",\"dns\",\"pullsecret\",\"hypershift\"])" }}
{{- end }}
{{- if not (and .Values.adapters (hasKey .Values.adapters "nodepool")) }}
{{- fail "adapters.nodepool is required - specify which adapters must be ready for nodepools (e.g., [\"validation\",\"hypershift\"])" }}
{{- end }}
- name: HYPERFLEET_CLUSTER_ADAPTERS
value: {{ .Values.adapters.cluster | default list | toJson | quote }}
- name: HYPERFLEET_NODEPOOL_ADAPTERS
value: {{ .Values.adapters.nodepool | default list | toJson | quote }}
{{- if .Values.env }}
{{- range .Values.env }}
- name: {{ .name }}
Expand Down
17 changes: 9 additions & 8 deletions charts/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,17 @@ auth:
# Override with: --set auth.jwksUrl="https://your-idp/.../.well-known/jwks.json"
jwksUrl: "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/certs"

# Adapter configuration
# Adapter configuration (REQUIRED)
# Configure which adapters must be ready for resources to be marked as "Ready"
# If not specified, defaults are used (see pkg/config/adapter.go)
# Both cluster and nodepool adapters MUST be specified - the application will not start without them
# Empty arrays [] are valid if you want no adapters required for the Ready state
adapters:
# Required adapters for cluster "Ready" state
# Default: ["validation", "dns", "pullsecret", "hypershift"]
cluster: []
# Required adapters for nodepool "Ready" state
# Default: ["validation", "hypershift"]
nodepool: []
# Required adapters for cluster "Ready" state (REQUIRED)
# Example: ["validation", "dns", "pullsecret", "hypershift"]
# cluster: []
# Required adapters for nodepool "Ready" state (REQUIRED)
# Example: ["validation", "hypershift"]
# nodepool: []

# ServiceMonitor for Prometheus Operator
# Enables automatic metrics discovery in clusters with Prometheus Operator
Expand Down
6 changes: 6 additions & 0 deletions cmd/hyperfleet-api/environments/framework.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ func (e *Env) Initialize() error {
os.Exit(1)
}

// Load adapter configuration from environment variables
if err := e.Config.LoadAdapters(); err != nil {
logger.WithError(ctx, err).Error("Failed to load adapter configuration")
os.Exit(1)
}

// each env will set db explicitly because the DB impl has a `once` init section
if err := envImpl.OverrideDatabase(&e.Database); err != nil {
logger.WithError(ctx, err).Error("Failed to configure Database")
Expand Down
9 changes: 9 additions & 0 deletions cmd/hyperfleet-api/environments/framework_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package environments

import (
"os"
"os/exec"
"reflect"
"testing"
Expand All @@ -23,6 +24,14 @@ func BenchmarkGetDynos(b *testing.B) {
}

func TestLoadServices(t *testing.T) {
// Set required adapter configuration for tests
if os.Getenv("HYPERFLEET_CLUSTER_ADAPTERS") == "" {
t.Setenv("HYPERFLEET_CLUSTER_ADAPTERS", `["validation","dns","pullsecret","hypershift"]`)
}
if os.Getenv("HYPERFLEET_NODEPOOL_ADAPTERS") == "" {
t.Setenv("HYPERFLEET_NODEPOOL_ADAPTERS", `["validation","hypershift"]`)
}

env := Environment()
err := env.AddFlags(pflag.CommandLine)
if err != nil {
Expand Down
45 changes: 25 additions & 20 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ export OPENAPI_SCHEMA_PATH=/path/to/custom-schema.yaml
- `LOG_LEVEL` - Logging level: `debug`, `info`, `warn`, `error` (default: `info`)
- `LOG_FORMAT` - Log format: `json`, `text` (default: `json`)

**Adapter Requirements:**
**Adapter Requirements (REQUIRED):**

Configure which adapters must be ready for resources to be marked as "Ready".
These environment variables are **required** - the application will not start without them.

**Default values** (if not configured):
- Cluster: `["validation","dns","pullsecret","hypershift"]`
- NodePool: `["validation","hypershift"]`
- `HYPERFLEET_CLUSTER_ADAPTERS` - JSON array of required cluster adapters (e.g., `["validation","dns","pullsecret","hypershift"]`)
- `HYPERFLEET_NODEPOOL_ADAPTERS` - JSON array of required nodepool adapters (e.g., `["validation","hypershift"]`)

**Option 1: Using structured values (Helm only, recommended)**
```yaml
Expand All @@ -107,22 +107,14 @@ adapters:
- hypershift
```

**Option 2: Using environment variables in Helm**
```yaml
# values.yaml
env:
- name: HYPERFLEET_CLUSTER_ADAPTERS
value: '["validation","dns","pullsecret","hypershift"]'
- name: HYPERFLEET_NODEPOOL_ADAPTERS
value: '["validation","hypershift"]'
```

**Option 3: Direct environment variable (non-Helm)**
**Option 2: Direct environment variable (non-Helm)**
```bash
export HYPERFLEET_CLUSTER_ADAPTERS='["validation","dns","pullsecret","hypershift"]'
export HYPERFLEET_NODEPOOL_ADAPTERS='["validation","hypershift"]'
```

**Note:** Empty arrays (`[]`) are valid if you want no adapters to be required for the Ready state.

## Kubernetes Deployment

### Using Helm Chart
Expand All @@ -136,7 +128,9 @@ Deploy with built-in PostgreSQL for development and testing:
```bash
helm install hyperfleet-api ./charts/ \
--namespace hyperfleet-system \
--create-namespace
--create-namespace \
--set adapters.cluster='{validation,dns,pullsecret,hypershift}' \
--set adapters.nodepool='{validation,hypershift}'
```

This creates:
Expand Down Expand Up @@ -168,7 +162,9 @@ helm install hyperfleet-api ./charts/ \
--namespace hyperfleet-system \
--set database.postgresql.enabled=false \
--set database.external.enabled=true \
--set database.external.secretName=hyperfleet-db-external
--set database.external.secretName=hyperfleet-db-external \
--set adapters.cluster='{validation,dns,pullsecret,hypershift}' \
--set adapters.nodepool='{validation,hypershift}'
```

#### Custom Image Deployment
Expand All @@ -180,7 +176,9 @@ helm install hyperfleet-api ./charts/ \
--namespace hyperfleet-system \
--set image.registry=quay.io \
--set image.repository=myuser/hyperfleet-api \
--set image.tag=v1.0.0
--set image.tag=v1.0.0 \
--set adapters.cluster='{validation,dns,pullsecret,hypershift}' \
--set adapters.nodepool='{validation,hypershift}'
```

#### Upgrade Deployment
Expand Down Expand Up @@ -211,6 +209,8 @@ helm uninstall hyperfleet-api --namespace hyperfleet-system
| `image.repository` | Image repository | `openshift-hyperfleet/hyperfleet-api` |
| `image.tag` | Image tag | `latest` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
| `adapters.cluster` | Required cluster adapters (REQUIRED) | - |
| `adapters.nodepool` | Required nodepool adapters (REQUIRED) | - |
| `auth.enableJwt` | Enable JWT authentication | `true` |
| `database.postgresql.enabled` | Enable built-in PostgreSQL | `true` |
| `database.external.enabled` | Use external database | `false` |
Expand Down Expand Up @@ -248,13 +248,16 @@ database:
enabled: true
secretName: hyperfleet-db-external

# Optional: customize adapter requirements (YAML table format)
# Required: specify adapter requirements
adapters:
cluster:
- validation
- dns
- pullsecret
- hypershift
nodepool:
- validation
- hypershift

replicaCount: 3

Expand Down Expand Up @@ -421,7 +424,9 @@ helm install hyperfleet-api ./charts/ \
--set image.tag=dev-abc123 \
--set auth.enableJwt=false \
--set database.postgresql.enabled=false \
--set database.external.enabled=true
--set database.external.enabled=true \
--set adapters.cluster='{validation,dns,pullsecret,hypershift}' \
--set adapters.nodepool='{validation,hypershift}'

# 6. Verify deployment
kubectl get pods
Expand Down
71 changes: 33 additions & 38 deletions pkg/config/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"encoding/json"
"fmt"
"log"
"os"
)
Expand All @@ -12,55 +13,49 @@ type AdapterRequirementsConfig struct {
RequiredNodePoolAdapters []string
}

// NewAdapterRequirementsConfig creates config from environment variables or defaults
func NewAdapterRequirementsConfig() *AdapterRequirementsConfig {
config := &AdapterRequirementsConfig{
RequiredClusterAdapters: getDefaultClusterAdapters(),
RequiredNodePoolAdapters: getDefaultNodePoolAdapters(),
// NewAdapterRequirementsConfig creates config from environment variables.
// Returns an error if required environment variables are not set.
// Required env vars: HYPERFLEET_CLUSTER_ADAPTERS, HYPERFLEET_NODEPOOL_ADAPTERS
// Format: JSON array, e.g., '["validation","dns","pullsecret","hypershift"]'
func NewAdapterRequirementsConfig() (*AdapterRequirementsConfig, error) {
config := &AdapterRequirementsConfig{}

if err := config.LoadFromEnv(); err != nil {
return nil, err
}

config.LoadFromEnv()
return config
return config, nil
}

// LoadFromEnv loads adapter lists from HYPERFLEET_CLUSTER_ADAPTERS and
// HYPERFLEET_NODEPOOL_ADAPTERS (JSON array format: '["adapter1","adapter2"]')
func (c *AdapterRequirementsConfig) LoadFromEnv() {
if clusterAdaptersStr := os.Getenv("HYPERFLEET_CLUSTER_ADAPTERS"); clusterAdaptersStr != "" {
var adapters []string
if err := json.Unmarshal([]byte(clusterAdaptersStr), &adapters); err == nil {
c.RequiredClusterAdapters = adapters
log.Printf("Loaded HYPERFLEET_CLUSTER_ADAPTERS from env: %v", adapters)
} else {
log.Printf("WARNING: Failed to parse HYPERFLEET_CLUSTER_ADAPTERS, using defaults: %v", err)
}
// Returns an error if the environment variables are not set or have invalid JSON.
func (c *AdapterRequirementsConfig) LoadFromEnv() error {
clusterAdaptersStr := os.Getenv("HYPERFLEET_CLUSTER_ADAPTERS")
if clusterAdaptersStr == "" {
return fmt.Errorf("HYPERFLEET_CLUSTER_ADAPTERS environment variable is required but not set")
}

if nodepoolAdaptersStr := os.Getenv("HYPERFLEET_NODEPOOL_ADAPTERS"); nodepoolAdaptersStr != "" {
var adapters []string
if err := json.Unmarshal([]byte(nodepoolAdaptersStr), &adapters); err == nil {
c.RequiredNodePoolAdapters = adapters
log.Printf("Loaded HYPERFLEET_NODEPOOL_ADAPTERS from env: %v", adapters)
} else {
log.Printf("WARNING: Failed to parse HYPERFLEET_NODEPOOL_ADAPTERS, using defaults: %v", err)
}
var clusterAdapters []string
if err := json.Unmarshal([]byte(clusterAdaptersStr), &clusterAdapters); err != nil {
return fmt.Errorf("failed to parse HYPERFLEET_CLUSTER_ADAPTERS: %w "+
"(expected JSON array, e.g., '[\"validation\",\"dns\"]')", err)
}
}
c.RequiredClusterAdapters = clusterAdapters
log.Printf("Loaded HYPERFLEET_CLUSTER_ADAPTERS from env: %v", clusterAdapters)

// Default cluster adapters: validation, dns, pullsecret, hypershift
func getDefaultClusterAdapters() []string {
return []string{
"validation",
"dns",
"pullsecret",
"hypershift",
nodepoolAdaptersStr := os.Getenv("HYPERFLEET_NODEPOOL_ADAPTERS")
if nodepoolAdaptersStr == "" {
return fmt.Errorf("HYPERFLEET_NODEPOOL_ADAPTERS environment variable is required but not set")
}
}

// Default nodepool adapters: validation, hypershift
func getDefaultNodePoolAdapters() []string {
return []string{
"validation",
"hypershift",
var nodepoolAdapters []string
if err := json.Unmarshal([]byte(nodepoolAdaptersStr), &nodepoolAdapters); err != nil {
return fmt.Errorf("failed to parse HYPERFLEET_NODEPOOL_ADAPTERS: %w "+
"(expected JSON array, e.g., '[\"validation\",\"hypershift\"]')", err)
}
c.RequiredNodePoolAdapters = nodepoolAdapters
log.Printf("Loaded HYPERFLEET_NODEPOOL_ADAPTERS from env: %v", nodepoolAdapters)

return nil
}
Loading