Populate internal GitHub IDP Config from CRD

This commit is contained in:
Joshua Casey
2024-04-02 21:53:03 -05:00
parent 349039ff5d
commit c9b61ef010
51 changed files with 3256 additions and 289 deletions

View File

@@ -12,29 +12,34 @@ import (
"go.pinniped.dev/internal/plog"
)
// MergeIDPConditions merges conditions into conditionsToUpdate. If returns true if it merged any error conditions.
func MergeIDPConditions(conditions []*metav1.Condition, observedGeneration int64, conditionsToUpdate *[]metav1.Condition, log plog.MinLogger) bool {
hadErrorCondition := false
// MergeConditions merges conditions into conditionsToUpdate.
// Note that LastTransitionTime refers to the time when the status changed,
// but ObservedGeneration should be the current generation for all conditions, since Pinniped should always check every condition.
// It returns true if any resulting condition has non-true status.
func MergeConditions(
conditions []*metav1.Condition,
observedGeneration int64,
conditionsToUpdate *[]metav1.Condition,
log plog.MinLogger,
lastTransitionTime metav1.Time,
) bool {
for i := range conditions {
cond := conditions[i].DeepCopy()
cond.LastTransitionTime = metav1.Now()
cond.LastTransitionTime = lastTransitionTime
cond.ObservedGeneration = observedGeneration
if mergeIDPCondition(conditionsToUpdate, cond) {
if mergeCondition(conditionsToUpdate, cond) {
log.Info("updated condition", "type", cond.Type, "status", cond.Status, "reason", cond.Reason, "message", cond.Message)
}
if cond.Status == metav1.ConditionFalse {
hadErrorCondition = true
}
}
sort.SliceStable(*conditionsToUpdate, func(i, j int) bool {
return (*conditionsToUpdate)[i].Type < (*conditionsToUpdate)[j].Type
})
return hadErrorCondition
return HadErrorCondition(conditions)
}
// mergeIDPCondition merges a new metav1.Condition into a slice of existing conditions. It returns true
// mergeCondition merges a new metav1.Condition into a slice of existing conditions. It returns true
// if the condition has meaningfully changed.
func mergeIDPCondition(existing *[]metav1.Condition, new *metav1.Condition) bool {
func mergeCondition(existing *[]metav1.Condition, new *metav1.Condition) bool {
// Find any existing condition with a matching type.
var old *metav1.Condition
for i := range *existing {
@@ -62,61 +67,7 @@ func mergeIDPCondition(existing *[]metav1.Condition, new *metav1.Condition) bool
return true
}
// Otherwise the entry is already up to date.
return false
}
// MergeConfigConditions merges conditions into conditionsToUpdate. It returns true if it merged any error conditions.
func MergeConfigConditions(conditions []*metav1.Condition, observedGeneration int64, conditionsToUpdate *[]metav1.Condition, log plog.MinLogger, now metav1.Time) bool {
hadErrorCondition := false
for i := range conditions {
cond := conditions[i].DeepCopy()
cond.LastTransitionTime = now
cond.ObservedGeneration = observedGeneration
if mergeConfigCondition(conditionsToUpdate, cond) {
log.Info("updated condition", "type", cond.Type, "status", cond.Status, "reason", cond.Reason, "message", cond.Message)
}
if cond.Status == metav1.ConditionFalse {
hadErrorCondition = true
}
}
sort.SliceStable(*conditionsToUpdate, func(i, j int) bool {
return (*conditionsToUpdate)[i].Type < (*conditionsToUpdate)[j].Type
})
return hadErrorCondition
}
// mergeConfigCondition merges a new metav1.Condition into a slice of existing conditions. It returns true
// if the condition has meaningfully changed.
func mergeConfigCondition(existing *[]metav1.Condition, new *metav1.Condition) bool {
// Find any existing condition with a matching type.
var old *metav1.Condition
for i := range *existing {
if (*existing)[i].Type == new.Type {
old = &(*existing)[i]
continue
}
}
// If there is no existing condition of this type, append this one and we're done.
if old == nil {
*existing = append(*existing, *new)
return true
}
// Set the LastTransitionTime depending on whether the status has changed.
new = new.DeepCopy()
if old.Status == new.Status {
new.LastTransitionTime = old.LastTransitionTime
}
// If anything has actually changed, update the entry and return true.
if !equality.Semantic.DeepEqual(old, new) {
*old = *new
return true
}
// Otherwise the entry is already up to date.
// Otherwise the entry is already up-to-date.
return false
}

View File

@@ -0,0 +1,158 @@
// Copyright 2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package conditionsutil
import (
"bytes"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"go.pinniped.dev/internal/plog"
)
func TestMergeIDPConditions(t *testing.T) {
twoHoursAgo := metav1.Time{Time: time.Now().Add(-2 * time.Hour)}
oneHourAgo := metav1.Time{Time: time.Now().Add(-1 * time.Hour)}
testTime := metav1.Now()
tests := []struct {
name string
newConditions []*metav1.Condition
conditionsToUpdate *[]metav1.Condition
observedGeneration int64
wantResult bool
wantLogSnippets []string
wantConditions []metav1.Condition
}{
{
name: "True -> False returns true",
newConditions: []*metav1.Condition{
{
Type: "UnchangedType",
Status: metav1.ConditionTrue,
Reason: "unchanged reason",
Message: "unchanged message",
},
{
Type: "FalseToTrueType",
Status: metav1.ConditionFalse,
Reason: "new reason",
Message: "new message",
},
{
Type: "NewType",
Status: metav1.ConditionTrue,
Reason: "new reason",
Message: "new message",
},
},
conditionsToUpdate: &[]metav1.Condition{
{
Type: "UnchangedType",
Status: metav1.ConditionTrue,
ObservedGeneration: int64(10),
LastTransitionTime: twoHoursAgo,
Reason: "unchanged reason",
Message: "unchanged message",
},
{
Type: "FalseToTrueType",
Status: metav1.ConditionTrue,
ObservedGeneration: int64(5),
LastTransitionTime: oneHourAgo,
Reason: "old reason",
Message: "old message",
},
},
observedGeneration: int64(100),
wantLogSnippets: []string{
`"message":"updated condition","type":"UnchangedType","status":"True"`,
`"message":"updated condition","type":"NewType","status":"True"`,
`"message":"updated condition","type":"FalseToTrueType","status":"False"`,
},
wantConditions: []metav1.Condition{
{
Type: "FalseToTrueType",
Status: metav1.ConditionFalse,
ObservedGeneration: int64(100),
LastTransitionTime: testTime,
Reason: "new reason",
Message: "new message",
},
{
Type: "NewType",
Status: metav1.ConditionTrue,
ObservedGeneration: int64(100),
LastTransitionTime: testTime,
Reason: "new reason",
Message: "new message",
},
{
Type: "UnchangedType",
Status: metav1.ConditionTrue,
ObservedGeneration: int64(100),
LastTransitionTime: twoHoursAgo,
Reason: "unchanged reason",
Message: "unchanged message",
},
},
wantResult: true,
},
{
name: "No logs when ObservedGeneration is unchanged",
newConditions: []*metav1.Condition{
{
Type: "UnchangedType",
Status: metav1.ConditionFalse,
Reason: "unchanged reason",
Message: "unchanged message",
},
},
conditionsToUpdate: &[]metav1.Condition{
{
Type: "UnchangedType",
Status: metav1.ConditionFalse,
ObservedGeneration: int64(10),
LastTransitionTime: twoHoursAgo,
Reason: "unchanged reason",
Message: "unchanged message",
},
},
observedGeneration: int64(10),
wantConditions: []metav1.Condition{
{
Type: "UnchangedType",
Status: metav1.ConditionFalse,
ObservedGeneration: int64(10),
LastTransitionTime: twoHoursAgo,
Reason: "unchanged reason",
Message: "unchanged message",
},
},
wantResult: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
var log bytes.Buffer
logger := plog.TestLogger(t, &log)
result := MergeConditions(tt.newConditions, tt.observedGeneration, tt.conditionsToUpdate, logger, testTime)
logString := log.String()
require.Equal(t, len(tt.wantLogSnippets), strings.Count(logString, "\n"))
for _, wantLog := range tt.wantLogSnippets {
require.Contains(t, logString, wantLog)
}
require.Equal(t, tt.wantResult, result)
require.Equal(t, tt.wantConditions, *tt.conditionsToUpdate)
})
}
}