Skip to content

Commit

Permalink
feat(controller): record verification history Stage (akuity#1645)
Browse files Browse the repository at this point in the history
Signed-off-by: Hidde Beydals <hidde@hhh.computer>
  • Loading branch information
hiddeco authored Mar 19, 2024
1 parent dd419ae commit a95eaa5
Show file tree
Hide file tree
Showing 12 changed files with 708 additions and 212 deletions.
464 changes: 263 additions & 201 deletions api/v1alpha1/generated.pb.go

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions api/v1alpha1/generated.proto

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

50 changes: 43 additions & 7 deletions api/v1alpha1/stage_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,19 +540,22 @@ type FreightReference struct {
// VerificationInfo is information about any verification process that was
// associated with this Freight for this Stage.
VerificationInfo *VerificationInfo `json:"verificationInfo,omitempty" protobuf:"bytes,5,opt,name=verificationInfo"`
// VerificationHistory is a stack of recent VerificationInfo. By default,
// the last ten VerificationInfo are stored.
VerificationHistory VerificationInfoStack `json:"verificationHistory,omitempty" protobuf:"bytes,7,rep,name=verificationHistory"`
}

type FreightReferenceStack []FreightReference

// Empty returns a bool indicating whether or not the FreightReferenceStack is
// empty. nil counts as empty.
// Empty returns a bool indicating whether the FreightReferenceStack is
// empty. Nil counts as empty.
func (f FreightReferenceStack) Empty() bool {
return len(f) == 0
}

// Pop removes and returns the leading element from a FreightReferenceStack. If
// the FreightReferenceStack is empty, the FreightReferenceStack is not modified
// and a empty FreightReference is returned instead. A boolean is also returned
// and an empty FreightReference is returned instead. A boolean is also returned
// indicating whether the returned FreightReference came from the top of the
// stack (true) or is a zero value for that type (false).
func (f *FreightReferenceStack) Pop() (FreightReference, bool) {
Expand All @@ -576,17 +579,17 @@ func (f FreightReferenceStack) Top() (FreightReference, bool) {
return item, true
}

// Push pushes one or more Freight onto the FreightStack. The order of
// Push pushes one or more Freight onto the FreightReferenceStack. The order of
// the new elements at the top of the stack will be equal to the order in which
// they were passed to this function. i.e. The first new element passed will be
// the element at the top of the stack. If resulting modification grow the depth
// of the stack beyond 10 elements, the stack is truncated at the bottom. i.e.
// Modified to contain only the top 10 elements.
func (f *FreightReferenceStack) Push(freight ...FreightReference) {
*f = append(freight, *f...)
const max = 10
if len(*f) > max {
*f = (*f)[:max]
const maxSize = 10
if len(*f) > maxSize {
*f = (*f)[:maxSize]
}
}

Expand Down Expand Up @@ -747,6 +750,39 @@ type VerificationInfo struct {
AnalysisRun *AnalysisRunReference `json:"analysisRun,omitempty" protobuf:"bytes,3,opt,name=analysisRun"`
}

type VerificationInfoStack []VerificationInfo

// UpdateOrPush updates the VerificationInfo with the same ID as the provided
// VerificationInfo or appends the provided VerificationInfo to the stack if no
// such VerificationInfo is found.
//
// The order of existing items in the stack is preserved, and new items without
// a matching ID are appended to the top of the stack. If the stack grows beyond
// 10 items, the bottom items are removed.
func (v *VerificationInfoStack) UpdateOrPush(info ...VerificationInfo) {
var newStack VerificationInfoStack
for _, i := range info {
var found bool
for vi, item := range *v {
if i.ID == item.ID {
(*v)[vi] = i
found = true
break
}
}
if !found {
newStack = append(newStack, i)
}
}

*v = append(newStack, *v...)

const maxSize = 10
if len(*v) > maxSize {
*v = (*v)[:maxSize]
}
}

// AnalysisRunReference is a reference to an AnalysisRun.
type AnalysisRunReference struct {
// Namespace is the namespace of the AnalysisRun.
Expand Down
49 changes: 49 additions & 0 deletions api/v1alpha1/stage_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,52 @@ func TestFreightReferenceStackPush(t *testing.T) {
})
}
}

func TestVerificationInfoStack_UpdateOrPush(t *testing.T) {
testCases := []struct {
name string
stack VerificationInfoStack
newInfo []VerificationInfo
expectedStack VerificationInfoStack
}{
{
name: "initial stack is nil",
stack: nil,
newInfo: []VerificationInfo{{ID: "foo"}, {ID: "bar"}},
expectedStack: VerificationInfoStack{{ID: "foo"}, {ID: "bar"}},
},
{
name: "initial stack is not nil",
stack: VerificationInfoStack{{ID: "foo"}},
newInfo: []VerificationInfo{{ID: "bar"}, {ID: "baz"}},
expectedStack: VerificationInfoStack{{ID: "bar"}, {ID: "baz"}, {ID: "foo"}},
},
{
name: "initial stack has matching IDs",
stack: VerificationInfoStack{{ID: "foo"}, {ID: "bar"}},
newInfo: []VerificationInfo{{ID: "bar", Phase: VerificationPhaseFailed}, {ID: "baz"}, {ID: "zab"}},
expectedStack: VerificationInfoStack{
{ID: "baz"},
{ID: "zab"},
{ID: "foo"},
{ID: "bar", Phase: VerificationPhaseFailed},
},
},
{
name: "initial stack is full",
stack: VerificationInfoStack{
{}, {}, {}, {}, {}, {}, {}, {}, {}, {},
},
newInfo: []VerificationInfo{{ID: "foo"}},
expectedStack: VerificationInfoStack{
{ID: "foo"}, {}, {}, {}, {}, {}, {}, {}, {}, {},
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
testCase.stack.UpdateOrPush(testCase.newInfo...)
require.Equal(t, testCase.expectedStack, testCase.stack)
})
}
}
28 changes: 28 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

140 changes: 140 additions & 0 deletions charts/kargo/crds/kargo.akuity.io_stages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,52 @@ spec:
the contents of the Freight. i.e. Two pieces of Freight can be compared for
equality by comparing their Names.
type: string
verificationHistory:
description: |-
VerificationHistory is a stack of recent VerificationInfo. By default,
the last ten VerificationInfo are stored.
items:
description: |-
VerificationInfo contains information about the currently running
Verification process.
properties:
analysisRun:
description: |-
AnalysisRun is a reference to the Argo Rollouts AnalysisRun that implements
the Verification process.
properties:
name:
description: Name is the name of the AnalysisRun.
type: string
namespace:
description: Namespace is the namespace of the AnalysisRun.
type: string
phase:
description: Phase is the last observed phase of the
AnalysisRun referenced by Name.
type: string
required:
- name
- namespace
- phase
type: object
id:
description: ID is the identifier of the Verification process.
type: string
message:
description: |-
Message may contain additional information about why the verification
process is in its current phase.
type: string
phase:
description: |-
Phase describes the current phase of the Verification process. Generally,
this will be a reflection of the underlying AnalysisRun's phase, however,
there are exceptions to this, such as in the case where an AnalysisRun
cannot be launched successfully.
type: string
type: object
type: array
verificationInfo:
description: |-
VerificationInfo is information about any verification process that was
Expand Down Expand Up @@ -819,6 +865,53 @@ spec:
the contents of the Freight. i.e. Two pieces of Freight can be compared for
equality by comparing their Names.
type: string
verificationHistory:
description: |-
VerificationHistory is a stack of recent VerificationInfo. By default,
the last ten VerificationInfo are stored.
items:
description: |-
VerificationInfo contains information about the currently running
Verification process.
properties:
analysisRun:
description: |-
AnalysisRun is a reference to the Argo Rollouts AnalysisRun that implements
the Verification process.
properties:
name:
description: Name is the name of the AnalysisRun.
type: string
namespace:
description: Namespace is the namespace of the AnalysisRun.
type: string
phase:
description: Phase is the last observed phase of
the AnalysisRun referenced by Name.
type: string
required:
- name
- namespace
- phase
type: object
id:
description: ID is the identifier of the Verification
process.
type: string
message:
description: |-
Message may contain additional information about why the verification
process is in its current phase.
type: string
phase:
description: |-
Phase describes the current phase of the Verification process. Generally,
this will be a reflection of the underlying AnalysisRun's phase, however,
there are exceptions to this, such as in the case where an AnalysisRun
cannot be launched successfully.
type: string
type: object
type: array
verificationInfo:
description: |-
VerificationInfo is information about any verification process that was
Expand Down Expand Up @@ -1040,6 +1133,53 @@ spec:
the contents of the Freight. i.e. Two pieces of Freight can be compared for
equality by comparing their Names.
type: string
verificationHistory:
description: |-
VerificationHistory is a stack of recent VerificationInfo. By default,
the last ten VerificationInfo are stored.
items:
description: |-
VerificationInfo contains information about the currently running
Verification process.
properties:
analysisRun:
description: |-
AnalysisRun is a reference to the Argo Rollouts AnalysisRun that implements
the Verification process.
properties:
name:
description: Name is the name of the AnalysisRun.
type: string
namespace:
description: Namespace is the namespace of the AnalysisRun.
type: string
phase:
description: Phase is the last observed phase of the
AnalysisRun referenced by Name.
type: string
required:
- name
- namespace
- phase
type: object
id:
description: ID is the identifier of the Verification
process.
type: string
message:
description: |-
Message may contain additional information about why the verification
process is in its current phase.
type: string
phase:
description: |-
Phase describes the current phase of the Verification process. Generally,
this will be a reflection of the underlying AnalysisRun's phase, however,
there are exceptions to this, such as in the case where an AnalysisRun
cannot be launched successfully.
type: string
type: object
type: array
verificationInfo:
description: |-
VerificationInfo is information about any verification process that was
Expand Down
8 changes: 8 additions & 0 deletions internal/controller/stages/stages.go
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,14 @@ func (r *reconciler) syncNormalStage(
}
}
}

// Update the verification history with the latest verification info.
// NOTE: We do this regardless of the phase of the verification process,
// to ensure we add any previous verification attempt which may have
// been recorded before we started tracking history.
if status.CurrentFreight.VerificationInfo != nil {
status.CurrentFreight.VerificationHistory.UpdateOrPush(*status.CurrentFreight.VerificationInfo)
}
}

// If health is not applicable or healthy
Expand Down
Loading

0 comments on commit a95eaa5

Please sign in to comment.