Skip to content

Commit ca9500d

Browse files
committed
Store the gate results on the deployer.
Healthchecks are passing.
1 parent 17df62e commit ca9500d

12 files changed

+226
-37
lines changed

api/v1alpha1/kustomizationautodeployer_types.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
)
2323

2424
const (
25-
// GatesClosedReason is set when further deployments can't continue because
25+
// GatesClosedReason is set when no commits will be applied because
2626
// the gates are currently closed.
2727
GatesClosedReason string = "GatesClosed"
2828

@@ -39,6 +39,10 @@ const (
3939
RevisionsErrorReason string = "RevisionsError"
4040
)
4141

42+
// GatesStatus contains a per-Gate, per check state of the configured gates in
43+
// the auto deployer.
44+
type GatesStatus map[string]map[string]bool
45+
4246
// HealthCheck is a Gate that fetches a URL and is open if the requests are
4347
// successful.
4448
type HealthCheck struct {
@@ -126,6 +130,9 @@ type KustomizationAutoDeployerStatus struct {
126130
// Conditions holds the conditions for the KustomizationAutoDeployer.
127131
// +optional
128132
Conditions []metav1.Condition `json:"conditions,omitempty"`
133+
134+
// Gates contains the state of the configured gates.
135+
Gates GatesStatus `json:"gates,omitempty"`
129136
}
130137

131138
//+kubebuilder:object:root=true

api/v1alpha1/zz_generated.deepcopy.go

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

config/crd/bases/flux.gitops.pro_kustomizationautodeployers.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,13 @@ spec:
180180
- type
181181
type: object
182182
type: array
183+
gates:
184+
additionalProperties:
185+
additionalProperties:
186+
type: boolean
187+
type: object
188+
description: Gates contains the state of the configured gates.
189+
type: object
183190
latestCommit:
184191
description: LatestCommit is the latest commit processed by the Kustomization.
185192
type: string

controllers/gates/check.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ import (
2626

2727
// Check checks the gates defined in the KustomizationAutoDeployer and returns
2828
// true if all gates are open.
29-
func Check(ctx context.Context, r *deployerv1.KustomizationAutoDeployer, configuredGates map[string]Gate) (bool, map[string]map[string]bool, error) {
29+
func Check(ctx context.Context, r *deployerv1.KustomizationAutoDeployer, configuredGates map[string]Gate) (bool, deployerv1.GatesStatus, error) {
3030
// Open if no Gates are defined.
3131
if len(r.Spec.Gates) == 0 {
3232
return true, nil, nil
3333
}
3434

35-
result := map[string]map[string]bool{}
35+
result := deployerv1.GatesStatus{}
3636
for _, gate := range r.Spec.Gates {
3737
checks, err := check(ctx, gate, r, configuredGates)
3838
if err != nil {

controllers/gates/check_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestCheck(t *testing.T) {
3737
name string
3838
deployer *deployerv1.KustomizationAutoDeployer
3939
open bool
40-
checks map[string]map[string]bool
40+
checks deployerv1.GatesStatus
4141
}{
4242
{
4343
name: "no gates should fail open",
@@ -58,7 +58,7 @@ func TestCheck(t *testing.T) {
5858
}
5959
}),
6060
open: true,
61-
checks: map[string]map[string]bool{"within scheduled hours": {"ScheduledGate": true}},
61+
checks: deployerv1.GatesStatus{"within scheduled hours": {"ScheduledGate": true}},
6262
},
6363
{
6464
name: "closed gate is closed",
@@ -74,7 +74,7 @@ func TestCheck(t *testing.T) {
7474
}
7575
}),
7676
open: false,
77-
checks: map[string]map[string]bool{"outwith scheduled hours": {"ScheduledGate": false}},
77+
checks: deployerv1.GatesStatus{"outwith scheduled hours": {"ScheduledGate": false}},
7878
},
7979
}
8080

controllers/gates/healthcheck/health_check.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func (g HealthCheckGate) Check(ctx context.Context, gate *deployerv1.Kustomizati
7676
}
7777

7878
// Interval returns the time after which to requeue this check.
79-
func (g HealthCheckGate) Interval(gate *deployerv1.KustomizationGate) time.Duration {
80-
return gate.HealthCheck.Interval.Duration
79+
func (g HealthCheckGate) Interval(gate *deployerv1.KustomizationGate) (time.Duration, error) {
80+
return gate.HealthCheck.Interval.Duration, nil
8181

8282
}

controllers/gates/healthcheck/health_check_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func TestHealthCheckGate_Interval(t *testing.T) {
9191
}
9292

9393
gen := New(logr.Discard(), nil)
94-
if i := gen.Interval(gate); i != time.Minute*5 {
94+
if i, _ := gen.Interval(gate); i != time.Minute*5 {
9595
t.Fatalf("Interval() got %v, want %v", i, time.Minute*5)
9696
}
9797
}

controllers/gates/interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type Gate interface {
4040
//
4141
// A Gate can return an empty time.Duration value if it should not be
4242
// rechecked after a period.
43-
Interval(*deployerv1.KustomizationGate) time.Duration
43+
Interval(*deployerv1.KustomizationGate) (time.Duration, error)
4444
}
4545

4646
// NoRequeueInterval is a simple default value that can be used to indicate that

controllers/gates/scheduled/scheduled_check.go

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,9 @@ type ScheduledGate struct {
5858

5959
// Check returns true if now is within the the Scheduled gate time duration.
6060
func (g ScheduledGate) Check(ctx context.Context, gate *deployerv1.KustomizationGate, _ *deployerv1.KustomizationAutoDeployer) (bool, error) {
61-
now := g.Clock()
6261
// TODO: Logging
63-
64-
open, err := parseAndMerge(now, gate.Name, "open", gate.Scheduled.Open)
65-
if err != nil {
66-
return false, err
67-
}
68-
69-
closed, err := parseAndMerge(now, gate.Name, "close", gate.Scheduled.Close)
62+
now := g.Clock()
63+
open, closed, err := parseScheduledTimes(now, gate.Name, gate.Scheduled)
7064
if err != nil {
7165
return false, err
7266
}
@@ -88,6 +82,34 @@ func parseAndMerge(now time.Time, name, phase, str string) (time.Time, error) {
8882
}
8983

9084
// Interval returns the time after which to requeue this check.
91-
func (g ScheduledGate) Interval(gate *deployerv1.KustomizationGate) time.Duration {
92-
return time.Minute * 3
85+
func (g ScheduledGate) Interval(gate *deployerv1.KustomizationGate) (time.Duration, error) {
86+
now := g.Clock()
87+
open, closed, err := parseScheduledTimes(now, gate.Name, gate.Scheduled)
88+
if err != nil {
89+
return 0, err
90+
}
91+
92+
if now.Before(open) {
93+
return open.Sub(now), nil
94+
}
95+
96+
if now.Before(closed) {
97+
return closed.Sub(now), nil
98+
}
99+
100+
return open.Add(time.Hour * 24).Sub(now), nil
101+
}
102+
103+
func parseScheduledTimes(now time.Time, name string, check *deployerv1.ScheduledCheck) (open time.Time, closed time.Time, err error) {
104+
open, err = parseAndMerge(now, name, "open", check.Open)
105+
if err != nil {
106+
return
107+
}
108+
109+
closed, err = parseAndMerge(now, name, "close", check.Close)
110+
if err != nil {
111+
return
112+
}
113+
114+
return
93115
}

controllers/gates/scheduled/scheduled_check_test.go

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,26 @@ func TestScheduledGate_Check_errors(t *testing.T) {
119119
}
120120

121121
func TestScheduledGate_Interval(t *testing.T) {
122-
// 9am on the 14th May 2023
123-
now := time.Date(2023, time.May, 14, 9, 0, 0, 0, time.UTC)
122+
intervalTests := []struct {
123+
now time.Time
124+
want time.Duration
125+
}{
126+
{
127+
// 09:00 on the 14th May 2023
128+
now: time.Date(2023, time.May, 14, 9, 0, 0, 0, time.UTC),
129+
want: time.Hour * 8,
130+
},
131+
{
132+
// 18:00 on the 14th May 2023
133+
now: time.Date(2023, time.May, 14, 18, 0, 0, 0, time.UTC),
134+
want: time.Hour * 1,
135+
},
136+
{
137+
// 20:00 on the 14th May 2023
138+
now: time.Date(2023, time.May, 14, 20, 0, 0, 0, time.UTC),
139+
want: time.Hour * 21, // 20:00 -> 00:00 + 17:00 = 21h
140+
},
141+
}
124142

125143
gate := &deployerv1.KustomizationGate{
126144
Name: "testing",
@@ -130,13 +148,22 @@ func TestScheduledGate_Interval(t *testing.T) {
130148
},
131149
}
132150

133-
gen := New(logr.Discard(), func(s *ScheduledGate) {
134-
s.Clock = func() time.Time {
135-
return now
136-
}
137-
})
151+
for _, tt := range intervalTests {
152+
t.Run(fmt.Sprintf("%v", tt.now), func(t *testing.T) {
153+
gen := New(logr.Discard(), func(s *ScheduledGate) {
154+
s.Clock = func() time.Time {
155+
return tt.now
156+
}
157+
})
158+
159+
i, err := gen.Interval(gate)
160+
if err != nil {
161+
t.Fatal(err)
162+
}
138163

139-
if i := gen.Interval(gate); i != time.Minute*5 {
140-
t.Fatalf("Interval() got %v, want %v", i, time.Minute*5)
164+
if i != tt.want {
165+
t.Fatalf("Interval() got %v, want %v", i, tt.want)
166+
}
167+
})
141168
}
142169
}

0 commit comments

Comments
 (0)