Skip to content

Commit ea0c554

Browse files
authored
Merge pull request #129 from jumpstarter-dev/last-seen
Implement last seen based exporter online status
2 parents 99d9fc5 + 584d668 commit ea0c554

File tree

14 files changed

+188
-145
lines changed

14 files changed

+188
-145
lines changed

.golangci.yml

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,45 @@
1+
version: "2"
12
run:
2-
timeout: 5m
33
allow-parallel-runners: true
4-
5-
issues:
6-
# don't skip warning about doc comments
7-
# don't exclude the default set of lint
8-
exclude-use-default: false
9-
# restore some of the defaults
10-
# (fill in the rest as needed)
11-
exclude-rules:
12-
- path: "api/*"
13-
linters:
14-
- lll
15-
- path: "internal/*"
16-
linters:
17-
- dupl
18-
- lll
194
linters:
20-
disable-all: true
5+
default: none
216
enable:
7+
- copyloopvar
228
- dupl
239
- errcheck
24-
- copyloopvar
2510
- ginkgolinter
2611
- goconst
2712
- gocyclo
28-
- gofmt
29-
- goimports
30-
- gosimple
3113
- govet
3214
- ineffassign
3315
- lll
3416
- misspell
3517
- nakedret
3618
- staticcheck
37-
- typecheck
3819
- unconvert
3920
- unparam
4021
- unused
22+
exclusions:
23+
generated: lax
24+
rules:
25+
- linters:
26+
- lll
27+
path: api/*
28+
- linters:
29+
- dupl
30+
- lll
31+
path: internal/*
32+
paths:
33+
- third_party$
34+
- builtin$
35+
- examples$
36+
formatters:
37+
enable:
38+
- gofmt
39+
- goimports
40+
exclusions:
41+
generated: lax
42+
paths:
43+
- third_party$
44+
- builtin$
45+
- examples$

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ GRPCURL = $(LOCALBIN)/grpcurl
180180
KUSTOMIZE_VERSION ?= v5.4.1
181181
CONTROLLER_TOOLS_VERSION ?= v0.16.3
182182
ENVTEST_VERSION ?= release-0.18
183-
GOLANGCI_LINT_VERSION ?= v1.61.0
183+
GOLANGCI_LINT_VERSION ?= v2.1.2
184184
KIND_VERSION ?= v0.27.0
185185
GRPCURL_VERSION ?= v1.9.2
186186

@@ -202,7 +202,7 @@ $(ENVTEST): $(LOCALBIN)
202202
.PHONY: golangci-lint
203203
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
204204
$(GOLANGCI_LINT): $(LOCALBIN)
205-
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))
205+
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))
206206

207207
.PHONY: grpcurl
208208
grpcurl: $(GRPCURL) ## Download grpcurl locally if necessary.

api/v1alpha1/exporter_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type ExporterStatus struct {
3737
Credential *corev1.LocalObjectReference `json:"credential,omitempty"`
3838
Devices []Device `json:"devices,omitempty"`
3939
LeaseRef *corev1.LocalObjectReference `json:"leaseRef,omitempty"`
40+
LastSeen metav1.Time `json:"lastSeen,omitempty"`
4041
Endpoint string `json:"endpoint,omitempty"`
4142
}
4243

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ spec:
135135
type: array
136136
endpoint:
137137
type: string
138+
lastSeen:
139+
format: date-time
140+
type: string
138141
leaseRef:
139142
description: |-
140143
LocalObjectReference contains enough information to let you locate the

internal/controller/client_controller.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
corev1 "k8s.io/api/core/v1"
2424
"k8s.io/apimachinery/pkg/runtime"
2525
ctrl "sigs.k8s.io/controller-runtime"
26-
"sigs.k8s.io/controller-runtime/pkg/client"
2726
kclient "sigs.k8s.io/controller-runtime/pkg/client"
2827
"sigs.k8s.io/controller-runtime/pkg/log"
2928

@@ -33,7 +32,7 @@ import (
3332

3433
// ClientReconciler reconciles a Client object
3534
type ClientReconciler struct {
36-
client.Client
35+
kclient.Client
3736
Scheme *runtime.Scheme
3837
Signer *oidc.Signer
3938
}

internal/controller/exporter_controller.go

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ package controller
1919
import (
2020
"context"
2121
"fmt"
22+
"time"
2223

2324
corev1 "k8s.io/api/core/v1"
25+
"k8s.io/apimachinery/pkg/api/meta"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2427
"k8s.io/apimachinery/pkg/runtime"
2528
ctrl "sigs.k8s.io/controller-runtime"
2629
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -72,6 +75,11 @@ func (r *ExporterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
7275
return ctrl.Result{}, err
7376
}
7477

78+
result, err := r.reconcileStatusConditionsOnline(ctx, &exporter)
79+
if err != nil {
80+
return ctrl.Result{}, err
81+
}
82+
7583
if err := r.reconcileStatusEndpoint(ctx, &exporter); err != nil {
7684
return ctrl.Result{}, err
7785
}
@@ -80,7 +88,7 @@ func (r *ExporterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
8088
return RequeueConflict(logger, ctrl.Result{}, err)
8189
}
8290

83-
return ctrl.Result{}, nil
91+
return result, nil
8492
}
8593

8694
func (r *ExporterReconciler) reconcileStatusCredential(
@@ -144,6 +152,64 @@ func (r *ExporterReconciler) reconcileStatusEndpoint(
144152
return nil
145153
}
146154

155+
// nolint:unparam
156+
func (r *ExporterReconciler) reconcileStatusConditionsOnline(
157+
_ context.Context,
158+
exporter *jumpstarterdevv1alpha1.Exporter,
159+
) (ctrl.Result, error) {
160+
var requeueAfter time.Duration = 0
161+
162+
if exporter.Status.LastSeen.IsZero() {
163+
meta.SetStatusCondition(&exporter.Status.Conditions, metav1.Condition{
164+
Type: string(jumpstarterdevv1alpha1.ExporterConditionTypeOnline),
165+
Status: metav1.ConditionFalse,
166+
ObservedGeneration: exporter.Generation,
167+
Reason: "Seen",
168+
Message: "Never seen",
169+
})
170+
// marking the exporter offline, no need to requeue
171+
} else if time.Since(exporter.Status.LastSeen.Time) > time.Minute {
172+
meta.SetStatusCondition(&exporter.Status.Conditions, metav1.Condition{
173+
Type: string(jumpstarterdevv1alpha1.ExporterConditionTypeOnline),
174+
Status: metav1.ConditionFalse,
175+
ObservedGeneration: exporter.Generation,
176+
Reason: "Seen",
177+
Message: "Last seen more than 1 minute ago",
178+
})
179+
// marking the exporter offline, no need to requeue
180+
} else {
181+
meta.SetStatusCondition(&exporter.Status.Conditions, metav1.Condition{
182+
Type: string(jumpstarterdevv1alpha1.ExporterConditionTypeOnline),
183+
Status: metav1.ConditionTrue,
184+
ObservedGeneration: exporter.Generation,
185+
Reason: "Seen",
186+
Message: "Lase seen less than 1 minute ago",
187+
})
188+
// marking the exporter online, requeue after 30 seconds
189+
requeueAfter = time.Second * 30
190+
}
191+
192+
if exporter.Status.Devices == nil {
193+
meta.SetStatusCondition(&exporter.Status.Conditions, metav1.Condition{
194+
Type: string(jumpstarterdevv1alpha1.ExporterConditionTypeRegistered),
195+
Status: metav1.ConditionFalse,
196+
ObservedGeneration: exporter.Generation,
197+
Reason: "Unregister",
198+
})
199+
} else {
200+
meta.SetStatusCondition(&exporter.Status.Conditions, metav1.Condition{
201+
Type: string(jumpstarterdevv1alpha1.ExporterConditionTypeRegistered),
202+
Status: metav1.ConditionTrue,
203+
ObservedGeneration: exporter.Generation,
204+
Reason: "Register",
205+
})
206+
}
207+
208+
return ctrl.Result{
209+
RequeueAfter: requeueAfter,
210+
}, nil
211+
}
212+
147213
// SetupWithManager sets up the controller with the Manager.
148214
func (r *ExporterReconciler) SetupWithManager(mgr ctrl.Manager) error {
149215
return ctrl.NewControllerManagedBy(mgr).

internal/controller/lease_controller.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -465,15 +465,13 @@ func filterOutOfflineExporters(matchingExporters []jumpstarterdevv1alpha1.Export
465465
onlineExporters := slices.DeleteFunc(
466466
matchingExporters,
467467
func(exporter jumpstarterdevv1alpha1.Exporter) bool {
468-
return !(true &&
469-
meta.IsStatusConditionTrue(
470-
exporter.Status.Conditions,
471-
string(jumpstarterdevv1alpha1.ExporterConditionTypeRegistered),
472-
) &&
473-
meta.IsStatusConditionTrue(
474-
exporter.Status.Conditions,
475-
string(jumpstarterdevv1alpha1.ExporterConditionTypeOnline),
476-
))
468+
return !true || !meta.IsStatusConditionTrue(
469+
exporter.Status.Conditions,
470+
string(jumpstarterdevv1alpha1.ExporterConditionTypeRegistered),
471+
) || !meta.IsStatusConditionTrue(
472+
exporter.Status.Conditions,
473+
string(jumpstarterdevv1alpha1.ExporterConditionTypeOnline),
474+
)
477475
},
478476
)
479477
return onlineExporters

internal/controller/lease_controller_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,13 @@ func setExporterOnlineConditions(ctx context.Context, name string, status metav1
339339
Status: status,
340340
Reason: "dummy",
341341
})
342+
if status == metav1.ConditionTrue {
343+
exporter.Status.Devices = []jumpstarterdevv1alpha1.Device{{}}
344+
exporter.Status.LastSeen = metav1.Now()
345+
} else {
346+
exporter.Status.Devices = nil
347+
exporter.Status.LastSeen = metav1.NewTime(metav1.Now().Add(-time.Minute * 2))
348+
}
342349
Expect(k8sClient.Status().Update(ctx, exporter)).To(Succeed())
343350
}
344351

internal/controller/secret_helpers.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"github.com/jumpstarter-dev/jumpstarter-controller/internal/oidc"
77
corev1 "k8s.io/api/core/v1"
88
"k8s.io/apimachinery/pkg/api/errors"
9-
apisv1 "k8s.io/apimachinery/pkg/apis/meta/v1"
109
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1110
"k8s.io/apimachinery/pkg/runtime"
1211
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -23,7 +22,7 @@ func ensureSecret(
2322
scheme *runtime.Scheme,
2423
signer *oidc.Signer,
2524
subject string,
26-
owner apisv1.Object,
25+
owner metav1.Object,
2726
) (*corev1.Secret, error) {
2827
logger := log.FromContext(ctx).WithName("ensureSecret")
2928
var secret corev1.Secret

0 commit comments

Comments
 (0)