Skip to content

Commit 531267e

Browse files
authored
Merge pull request #140 from jumpstarter-dev/add-hooks
Add pre/post lease hooks
2 parents 9505582 + 657efd2 commit 531267e

File tree

111 files changed

+12694
-476
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+12694
-476
lines changed

.github/workflows/controller-tests.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ jobs:
1616
with:
1717
fetch-depth: 0
1818

19+
- name: Cache controller bin directory
20+
uses: actions/cache@v4
21+
with:
22+
path: controller/bin/
23+
key: ${{ runner.os }}-controller-bin-${{ hashFiles('controller/go.mod') }}
24+
restore-keys: |
25+
${{ runner.os }}-controller-bin-
26+
1927
- name: Run controller tests
2028
working-directory: controller
2129
run: make test

.github/workflows/e2e.yaml

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,84 @@ jobs:
5050
steps:
5151
- name: Checkout repository
5252
uses: actions/checkout@v4
53-
53+
5454
- name: Install uv
5555
uses: astral-sh/setup-uv@v7
56-
56+
5757
- name: Install Go
5858
uses: actions/setup-go@v5
5959
with:
60-
go-version: '1.22'
61-
60+
go-version: "1.22"
61+
6262
- name: Setup e2e test environment
6363
run: make e2e-setup
6464
env:
6565
CI: true
6666
METHOD: ${{ matrix.method }}
67-
67+
6868
- name: Run e2e tests
6969
run: make e2e-run
7070
env:
7171
CI: true
7272
METHOD: ${{ matrix.method }}
73+
74+
# ============================================================================
75+
# Compatibility tests: cross-version interop between controller and client/exporter
76+
# These jobs can be removed once 0.7.x controller support is no longer needed.
77+
# ============================================================================
78+
79+
e2e-compat-old-controller:
80+
needs: changes
81+
if: needs.changes.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch'
82+
runs-on: ubuntu-24.04
83+
timeout-minutes: 60
84+
steps:
85+
- name: Checkout repository
86+
uses: actions/checkout@v4
87+
88+
- name: Install uv
89+
uses: astral-sh/setup-uv@v7
90+
91+
- name: Install Go
92+
uses: actions/setup-go@v5
93+
with:
94+
go-version: "1.22"
95+
96+
- name: Setup compat environment (old controller v0.7.0)
97+
run: make e2e-compat-setup COMPAT_SCENARIO=old-controller
98+
env:
99+
CI: true
100+
COMPAT_CONTROLLER_TAG: v0.7.0
101+
102+
- name: Run compat tests (old controller + new client/exporter)
103+
run: make e2e-compat-run COMPAT_TEST=old-controller
104+
env:
105+
CI: true
106+
107+
e2e-compat-old-client:
108+
needs: changes
109+
if: needs.changes.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch'
110+
runs-on: ubuntu-24.04
111+
timeout-minutes: 60
112+
steps:
113+
- name: Checkout repository
114+
uses: actions/checkout@v4
115+
116+
- name: Install uv
117+
uses: astral-sh/setup-uv@v7
118+
119+
- name: Install Go
120+
uses: actions/setup-go@v5
121+
with:
122+
go-version: "1.22"
123+
124+
- name: Setup compat environment (old client v0.7.0)
125+
run: make e2e-compat-setup COMPAT_SCENARIO=old-client
126+
env:
127+
CI: true
128+
COMPAT_CLIENT_VERSION: "0.7.1"
129+
130+
- name: Run compat tests (new controller + old client/exporter)
131+
run: make e2e-compat-run COMPAT_TEST=old-client
132+
env:
133+
CI: true

Makefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,23 @@ e2e-clean:
169169
.PHONY: test-e2e
170170
test-e2e: e2e-run
171171

172+
# Compatibility E2E testing (cross-version tests, separate from main e2e)
173+
COMPAT_SCENARIO ?= old-controller
174+
COMPAT_TEST ?= old-controller
175+
COMPAT_CONTROLLER_TAG ?= v0.7.0
176+
COMPAT_CLIENT_VERSION ?= 0.7.1
177+
178+
.PHONY: e2e-compat-setup
179+
e2e-compat-setup:
180+
@echo "Setting up compat e2e (scenario: $(COMPAT_SCENARIO))..."
181+
@COMPAT_SCENARIO=$(COMPAT_SCENARIO) COMPAT_CONTROLLER_TAG=$(COMPAT_CONTROLLER_TAG) \
182+
COMPAT_CLIENT_VERSION=$(COMPAT_CLIENT_VERSION) bash e2e/compat/setup.sh
183+
184+
.PHONY: e2e-compat-run
185+
e2e-compat-run:
186+
@echo "Running compat e2e (test: $(COMPAT_TEST))..."
187+
@COMPAT_TEST=$(COMPAT_TEST) bash e2e/compat/run.sh
188+
172189
# Per-project clean targets
173190
.PHONY: clean-python clean-protocol clean-controller clean-e2e
174191
clean-python:

controller/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*.so
66
*.dylib
77
bin/*
8+
deploy/operator/bin/
89
Dockerfile.cross
910

1011
# Test binary, built with `go test -c`

controller/Makefile

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,20 @@ help: ## Display this help.
6363
.PHONY: manifests
6464
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
6565
$(CONTROLLER_GEN) rbac:roleName=jumpstarter-manager-role crd webhook paths="./api/..." paths="./internal/..." \
66-
output:crd:artifacts:config=deploy/helm/jumpstarter/crds/ \
66+
output:crd:artifacts:config=deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/crds/ \
6767
output:rbac:artifacts:config=deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/rbac/
6868

69-
cp deploy/helm/jumpstarter/crds/* deploy/operator/config/crd/bases/
69+
# Add ArgoCD sync-wave annotation to RBAC role for proper deployment ordering (PR #207)
70+
@awk '/^ name: jumpstarter-manager-role$$/{print; print " annotations:"; print " argocd.argoproj.io/sync-wave: \"-1\""; next}1' \
71+
deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/rbac/role.yaml > \
72+
deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/rbac/role.yaml.tmp && \
73+
mv deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/rbac/role.yaml.tmp \
74+
deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/rbac/role.yaml
75+
76+
cp deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/crds/* deploy/operator/config/crd/bases/
77+
78+
# Regenerate operator install.yaml to include updated CRDs
79+
$(MAKE) -C deploy/operator build-installer
7080

7181
.PHONY: generate
7282
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
@@ -236,7 +246,7 @@ GRPCURL = $(LOCALBIN)/grpcurl
236246
## Tool Versions
237247
KUSTOMIZE_VERSION ?= v5.4.1
238248
CONTROLLER_TOOLS_VERSION ?= v0.16.3
239-
ENVTEST_VERSION ?= release-0.18
249+
ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}')
240250
GOLANGCI_LINT_VERSION ?= v2.5.0
241251
KIND_VERSION ?= v0.27.0
242252
GRPCURL_VERSION ?= v1.9.2

controller/api/v1alpha1/exporter_helpers.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"strings"
55

66
cpb "github.com/jumpstarter-dev/jumpstarter-controller/internal/protocol/jumpstarter/client/v1"
7+
pb "github.com/jumpstarter-dev/jumpstarter-controller/internal/protocol/jumpstarter/v1"
78
"github.com/jumpstarter-dev/jumpstarter-controller/internal/service/utils"
89
"k8s.io/apimachinery/pkg/api/meta"
910
kclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -25,13 +26,37 @@ func (e *Exporter) Usernames(prefix string) []string {
2526
}
2627

2728
func (e *Exporter) ToProtobuf() *cpb.Exporter {
28-
// get online status from conditions
29+
// get online status from conditions (deprecated, kept for backward compatibility)
2930
isOnline := meta.IsStatusConditionTrue(e.Status.Conditions, string(ExporterConditionTypeOnline))
3031

3132
return &cpb.Exporter{
32-
Name: utils.UnparseExporterIdentifier(kclient.ObjectKeyFromObject(e)),
33-
Labels: e.Labels,
34-
Online: isOnline,
33+
Name: utils.UnparseExporterIdentifier(kclient.ObjectKeyFromObject(e)),
34+
Labels: e.Labels,
35+
Online: isOnline,
36+
Status: stringToProtoStatus(e.Status.ExporterStatusValue),
37+
StatusMessage: e.Status.StatusMessage,
38+
}
39+
}
40+
41+
// stringToProtoStatus converts the CRD string value to the proto ExporterStatus enum
42+
func stringToProtoStatus(state string) pb.ExporterStatus {
43+
switch state {
44+
case ExporterStatusOffline:
45+
return pb.ExporterStatus_EXPORTER_STATUS_OFFLINE
46+
case ExporterStatusAvailable:
47+
return pb.ExporterStatus_EXPORTER_STATUS_AVAILABLE
48+
case ExporterStatusBeforeLeaseHook:
49+
return pb.ExporterStatus_EXPORTER_STATUS_BEFORE_LEASE_HOOK
50+
case ExporterStatusLeaseReady:
51+
return pb.ExporterStatus_EXPORTER_STATUS_LEASE_READY
52+
case ExporterStatusAfterLeaseHook:
53+
return pb.ExporterStatus_EXPORTER_STATUS_AFTER_LEASE_HOOK
54+
case ExporterStatusBeforeLeaseHookFailed:
55+
return pb.ExporterStatus_EXPORTER_STATUS_BEFORE_LEASE_HOOK_FAILED
56+
case ExporterStatusAfterLeaseHookFailed:
57+
return pb.ExporterStatus_EXPORTER_STATUS_AFTER_LEASE_HOOK_FAILED
58+
default:
59+
return pb.ExporterStatus_EXPORTER_STATUS_UNSPECIFIED
3560
}
3661
}
3762

controller/api/v1alpha1/exporter_types.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ type ExporterStatus struct {
3838
LeaseRef *corev1.LocalObjectReference `json:"leaseRef,omitempty"`
3939
LastSeen metav1.Time `json:"lastSeen,omitempty"`
4040
Endpoint string `json:"endpoint,omitempty"`
41+
// ExporterStatusValue is the current operational status reported by the exporter
42+
// +kubebuilder:validation:Enum=Unspecified;Offline;Available;BeforeLeaseHook;LeaseReady;AfterLeaseHook;BeforeLeaseHookFailed;AfterLeaseHookFailed
43+
ExporterStatusValue string `json:"exporterStatus,omitempty"`
44+
// StatusMessage is an optional human-readable message describing the current state
45+
StatusMessage string `json:"statusMessage,omitempty"`
4146
}
4247

4348
type ExporterConditionType string
@@ -47,8 +52,22 @@ const (
4752
ExporterConditionTypeOnline ExporterConditionType = "Online"
4853
)
4954

55+
// ExporterStatus values - PascalCase for Kubernetes, converted from proto ALL_CAPS
56+
const (
57+
ExporterStatusUnspecified = "Unspecified"
58+
ExporterStatusOffline = "Offline"
59+
ExporterStatusAvailable = "Available"
60+
ExporterStatusBeforeLeaseHook = "BeforeLeaseHook"
61+
ExporterStatusLeaseReady = "LeaseReady"
62+
ExporterStatusAfterLeaseHook = "AfterLeaseHook"
63+
ExporterStatusBeforeLeaseHookFailed = "BeforeLeaseHookFailed"
64+
ExporterStatusAfterLeaseHookFailed = "AfterLeaseHookFailed"
65+
)
66+
5067
// +kubebuilder:object:root=true
5168
// +kubebuilder:subresource:status
69+
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.exporterStatus"
70+
// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.statusMessage",priority=1
5271

5372
// Exporter is the Schema for the exporters API
5473
type Exporter struct {

controller/deploy/helm/jumpstarter/crds/jumpstarter.dev_clients.yaml renamed to controller/deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/crds/jumpstarter.dev_clients.yaml

File renamed without changes.

controller/deploy/helm/jumpstarter/crds/jumpstarter.dev_exporteraccesspolicies.yaml renamed to controller/deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/crds/jumpstarter.dev_exporteraccesspolicies.yaml

File renamed without changes.

controller/deploy/helm/jumpstarter/crds/jumpstarter.dev_exporters.yaml renamed to controller/deploy/helm/jumpstarter/charts/jumpstarter-controller/templates/crds/jumpstarter.dev_exporters.yaml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,15 @@ spec:
1414
singular: exporter
1515
scope: Namespaced
1616
versions:
17-
- name: v1alpha1
17+
- additionalPrinterColumns:
18+
- jsonPath: .status.exporterStatus
19+
name: Status
20+
type: string
21+
- jsonPath: .status.statusMessage
22+
name: Message
23+
priority: 1
24+
type: string
25+
name: v1alpha1
1826
schema:
1927
openAPIV3Schema:
2028
description: Exporter is the Schema for the exporters API
@@ -133,6 +141,19 @@ spec:
133141
type: array
134142
endpoint:
135143
type: string
144+
exporterStatus:
145+
description: ExporterStatusValue is the current operational status
146+
reported by the exporter
147+
enum:
148+
- Unspecified
149+
- Offline
150+
- Available
151+
- BeforeLeaseHook
152+
- LeaseReady
153+
- AfterLeaseHook
154+
- BeforeLeaseHookFailed
155+
- AfterLeaseHookFailed
156+
type: string
136157
lastSeen:
137158
format: date-time
138159
type: string
@@ -152,6 +173,10 @@ spec:
152173
type: string
153174
type: object
154175
x-kubernetes-map-type: atomic
176+
statusMessage:
177+
description: StatusMessage is an optional human-readable message describing
178+
the current state
179+
type: string
155180
type: object
156181
type: object
157182
served: true

0 commit comments

Comments
 (0)