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
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pipeline {
if [[ "${BRANCH_NAME}" = "develop" ]]; then
export IMAGE_TAG="latest"
else
export RELEASE_VERSION="${BRANCH_NAME}"
export RELEASE_VERSION="$(echo "${BRANCH_NAME}" | tr '/' '-')"
fi
fi

Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ endif
OPERATOR_SDK_VERSION ?= v1.33.0
# Image URL to use all building/pushing image targets
#IMG ?= docker.io/layer7api/layer7-operator:v$(VERSION)
IMG ?= $(IMAGE_TAG_BASE):$(VERSION)
# Sanitize VERSION for use as a Docker image tag: slashes (from branch names like
# feature/foo) are not valid in tags and must be replaced with hyphens.
DOCKER_VERSION := $(subst /,-,$(VERSION))
IMG ?= $(IMAGE_TAG_BASE):$(DOCKER_VERSION)
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.30.0

Expand Down Expand Up @@ -218,7 +221,7 @@ build: manifests generate fmt vet ## Build manager binary.

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./cmd/main.go --zap-log-level=5
go run ./cmd/main.go --zap-log-level=5 --leader-elect=false

.PHONY: docker-build
docker-build: dockerfile #test ## Build docker image with the manager.
Expand Down
38 changes: 38 additions & 0 deletions api/v1/gateway_types.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) 2026 Broadcom Inc. and its subsidiaries. All Rights Reserved.
/*
Copyright 2021.

Expand Down Expand Up @@ -64,6 +65,20 @@ type GatewayList struct {
Items []Gateway `json:"items"`
}

// MigrationStatus tracks the state of the pre-upgrade database migration job.
// It is persisted in Gateway.Status so that completed migrations survive job
// deletion and are not re-run on daily reconciles or operator restarts.
type MigrationStatus struct {
// SpecHash is a short hash of the migration-relevant spec fields (image,
// effective jdbcUrl, clearLocks). When any of these change the hash changes
// and a fresh migration job is triggered.
SpecHash string `json:"specHash,omitempty"`
// Complete indicates that the migration job succeeded for the current SpecHash.
// Once true, GatewayMigrationJob skips job management entirely and the
// Deployment step is unblocked — regardless of whether the Job still exists.
Complete bool `json:"complete,omitempty"`
}

// GatewayStatus defines the observed state of Gateways
type GatewayStatus struct {
// Host is the Gateway Cluster Hostname
Expand Down Expand Up @@ -119,6 +134,8 @@ type GatewayStatus struct {
LastAppliedExternalCerts map[string][]string `json:"lastAppliedExternalCerts,omitempty"`
// LastAppliedOtkFipsCerts tracks which OTK FIPS user certificates have been applied
LastAppliedOtkFipsCerts map[string][]string `json:"lastAppliedOtkFipsCerts,omitempty"`
// MigrationStatus tracks the state of the pre-upgrade database migration job.
MigrationStatus MigrationStatus `json:"migrationStatus,omitempty"`
}

// GatewayState tracks the status of Gateway Resources
Expand Down Expand Up @@ -688,6 +705,27 @@ type Database struct {
Password string `json:"password,omitempty"`
// LiquibaseLogLevel
LiquibaseLogLevel LiquibaseLogLevel `json:"liquibaseLogLevel,omitempty"`
// MigrationJob for pre-upgrade schema updates
MigrationJob MigrationJob `json:"migrationJob,omitempty"`
}

// MigrationJob configures the pre-upgrade database migration job
type MigrationJob struct {
// Enabled or disabled
Enabled bool `json:"enabled,omitempty"`
// JDBCUrl overrides the main database.jdbcUrl for the migration job (e.g. to bypass a proxy).
// Only applies in diskless mode (disklessConfig.disabled: false, the default).
// In non-diskless mode the entrypoint reads the JDBC URL from the mounted node.properties
// file and this field has no effect — node.properties always wins, consistent with Helm behavior.
JDBCUrl string `json:"jdbcUrl,omitempty"`
// ClearLocks forces release of any stuck Liquibase locks before applying
// schema updates. Use with caution: forcefully releasing a lock while
// another process is actively updating the schema can corrupt the database.
ClearLocks bool `json:"clearLocks,omitempty"`
// ActiveDeadlineSeconds is the max duration each pod attempt is allowed to run.
// The job may retry once (backoffLimit=1), so total elapsed time can be up to
// 2× this value. Defaults to 300 seconds (5 minutes) per attempt.
ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty"`
}

// Restman is a Gateway Management interface that can be automatically provisioned.
Expand Down
6 changes: 6 additions & 0 deletions api/v1/gateway_webhook.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) 2026 Broadcom Inc. and its subsidiaries. All Rights Reserved.
/*
Copyright 2021.

Expand Down Expand Up @@ -193,6 +194,11 @@ func validateGateway(r *Gateway) (admission.Warnings, error) {
}
}

if r.Spec.App.Management.Database.MigrationJob.Enabled &&
!r.Spec.App.Management.Database.Enabled {
return warnings, fmt.Errorf("migrationJob.enabled requires database.enabled: true")
}

if r.Spec.App.Management.Service.Enabled {
if r.Spec.App.Management.Service.Type != v1.ServiceTypeClusterIP && r.Spec.App.Management.Service.Type != v1.ServiceTypeLoadBalancer && r.Spec.App.Management.Service.Type != v1.ServiceTypeNodePort {
return warnings, fmt.Errorf("please specify a valid management service type, valid types are LoadBalancer, ClusterIP and NodePort")
Expand Down
40 changes: 39 additions & 1 deletion api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions config/crd/bases/security.brcmlabs.com_gateways.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3534,6 +3534,26 @@ spec:
liquibaseLogLevel:
description: LiquibaseLogLevel
type: string
migrationJob:
description: MigrationJob for pre-upgrade schema updates
properties:
activeDeadlineSeconds:
description: ActiveDeadlineSeconds is the max duration
each pod attempt is allowed to...
format: int64
type: integer
clearLocks:
description: ClearLocks forces release of any stuck
Liquibase locks before applying...
type: boolean
enabled:
description: Enabled or disabled
type: boolean
jdbcUrl:
description: JDBCUrl overrides the main database.jdbcUrl
for the migration job (e.g.
type: string
type: object
password:
description: Password MySQL - can be set in management.secretName
type: string
Expand Down Expand Up @@ -6765,6 +6785,19 @@ spec:
description: Management Pod is a Gateway with a special annotation
is used as a...
type: string
migrationStatus:
description: MigrationStatus tracks the state of the pre-upgrade database
migration job.
properties:
complete:
description: Complete indicates that the migration job succeeded
for the current...
type: boolean
specHash:
description: SpecHash is a short hash of the migration-relevant
spec fields (image,...
type: string
type: object
phase:
description: PodPhase is a label for the condition of a pod at the
current time.
Expand Down
109 changes: 109 additions & 0 deletions docs/gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -9848,6 +9848,13 @@ Database configuration for the Gateway
LiquibaseLogLevel<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#gatewayspecappmanagementdatabasemigrationjob">migrationJob</a></b></td>
<td>object</td>
<td>
MigrationJob for pre-upgrade schema updates<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>password</b></td>
<td>string</td>
Expand All @@ -9866,6 +9873,63 @@ Database configuration for the Gateway
</table>


### Gateway.spec.app.management.database.migrationJob
<sup><sup>[↩ Parent](#gatewayspecappmanagementdatabase)</sup></sup>



MigrationJob for pre-upgrade schema updates

<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>activeDeadlineSeconds</b></td>
<td>integer</td>
<td>
ActiveDeadlineSeconds is the max duration each pod attempt is allowed to run.
The job may retry once (backoffLimit=1), so total elapsed time can be up to
2× this value. Defaults to 300 seconds (5 minutes) per attempt.<br/>
<br/>
<i>Format</i>: int64<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>clearLocks</b></td>
<td>boolean</td>
<td>
ClearLocks forces release of any stuck Liquibase locks before applying
schema updates. Use with caution: forcefully releasing a lock while
another process is actively updating the schema can corrupt the database.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>enabled</b></td>
<td>boolean</td>
<td>
Enabled or disabled<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>jdbcUrl</b></td>
<td>string</td>
<td>
JDBCUrl overrides the main database.jdbcUrl for the migration job (e.g. to bypass a proxy).
Only applies in diskless mode (disklessConfig.disabled: false, the default).
In non-diskless mode the entrypoint reads the JDBC URL from the mounted node.properties
file and this field has no effect — node.properties always wins, consistent with Helm behavior.<br/>
</td>
<td>false</td>
</tr></tbody>
</table>


### Gateway.spec.app.management.disklessConfig
<sup><sup>[↩ Parent](#gatewayspecappmanagement)</sup></sup>

Expand Down Expand Up @@ -18720,6 +18784,13 @@ GatewayStatus defines the observed state of Gateways
management service and applying singleton resources<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#gatewaystatusmigrationstatus">migrationStatus</a></b></td>
<td>object</td>
<td>
MigrationStatus tracks the state of the pre-upgrade database migration job.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>phase</b></td>
<td>string</td>
Expand Down Expand Up @@ -18932,6 +19003,44 @@ GatewayState tracks the status of Gateway Resources
</table>


### Gateway.status.migrationStatus
<sup><sup>[↩ Parent](#gatewaystatus)</sup></sup>



MigrationStatus tracks the state of the pre-upgrade database migration job.

<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>complete</b></td>
<td>boolean</td>
<td>
Complete indicates that the migration job succeeded for the current SpecHash.
Once true, GatewayMigrationJob skips job management entirely and the
Deployment step is unblocked — regardless of whether the Job still exists.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>specHash</b></td>
<td>string</td>
<td>
SpecHash is a short hash of the migration-relevant spec fields (image,
effective jdbcUrl, clearLocks). When any of these change the hash changes
and a fresh migration job is triggered.<br/>
</td>
<td>false</td>
</tr></tbody>
</table>


### Gateway.status.repositoryStatus[index]
<sup><sup>[↩ Parent](#gatewaystatus)</sup></sup>

Expand Down
6 changes: 4 additions & 2 deletions internal/controller/gateway/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (
"go.opentelemetry.io/otel/metric"
appsv1 "k8s.io/api/apps/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
policyv1 "k8s.io/api/policy/v1"
Expand Down Expand Up @@ -100,6 +101,7 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
{reconcile.PodDisruptionBudget, "podDisruptionBudget"},
{reconcile.GatewayStatus, "gatewayStatus"},
{reconcile.ConfigMaps, "configMaps"},
{reconcile.GatewayMigrationJob, "migration job"},
{reconcile.Deployment, "deployment"},
{reconcile.ManagementPod, "management pod"},
{reconcile.HandleEphemeralRestarts, "ephemeral restart detection"},
Expand Down Expand Up @@ -138,7 +140,6 @@ func (r *GatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
}

_ = captureMetrics(ctx, params, start, false, "")

return ctrl.Result{RequeueAfter: 12 * time.Hour}, nil
}

Expand All @@ -163,7 +164,8 @@ func (r *GatewayReconciler) SetupWithManager(mgr ctrl.Manager) error {
Owns(&networkingv1.Ingress{}).
Owns(&appsv1.Deployment{}).
Owns(&policyv1.PodDisruptionBudget{}).
Owns(&autoscalingv2.HorizontalPodAutoscaler{})
Owns(&autoscalingv2.HorizontalPodAutoscaler{}).
Owns(&batchv1.Job{})

repo := &metav1.PartialObjectMetadata{}
repo.SetGroupVersionKind(schema.GroupVersionKind{
Expand Down
Loading
Loading