Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Builder UpToDate Condition #1370

Merged
merged 3 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/builder.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ spec:
- name: Ready
type: string
jsonPath: ".status.conditions[?(@.type==\"Ready\")].status"
- name: UpToDate
type: string
jsonPath: ".status.conditions[?(@.type==\"UpToDate\")].status"
conversion:
strategy: Webhook
webhook:
Expand Down
3 changes: 3 additions & 0 deletions config/clusterbuilder.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ spec:
- name: Ready
type: string
jsonPath: ".status.conditions[?(@.type==\"Ready\")].status"
- name: UpToDate
type: string
jsonPath: ".status.conditions[?(@.type==\"UpToDate\")].status"
names:
kind: ClusterBuilder
listKind: ClusterBuilderList
Expand Down
10 changes: 10 additions & 0 deletions docs/builders.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,13 @@ version) in the following order:
`paketo-buildpacks/gradle` is a sub-buildpack of `paketo-buildpacks/java`)
1. As a sub-buildpack of any ClusterBuildpacks
1. As a sub-buildpack in the ClusterStore specified in the Builder spec.

### <a id='status'></a>Builder Status Conditions

Builders and ClusterBuilders have two Conditions that represent the overall status of the Builder.

The 'Ready' condition is used to show that the Builder is able to be used in Builds

The 'UpToDate' condition indicates whether the most recent reconcile of the Builder
was successful. When this condition is false, that means that the Builder may not have the
latest Stack or Buildpacks due to ongoing reconcile failures.
21 changes: 20 additions & 1 deletion pkg/apis/build/v1alpha2/builder_lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ func (bs *BuilderStatus) BuilderRecord(record BuilderRecord) {
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
},
{
Type: ConditionUpToDate,
Status: corev1.ConditionTrue,
LastTransitionTime: corev1alpha1.VolatileTime{Inner: v1.Now()},
},
}
bs.Order = record.Order
bs.ObservedStoreGeneration = record.ObservedStoreGeneration
Expand All @@ -38,12 +43,26 @@ func (bs *BuilderStatus) BuilderRecord(record BuilderRecord) {
}

func (bs *BuilderStatus) ErrorCreate(err error) {

readyCondition := corev1alpha1.Condition{
LastTransitionTime: corev1alpha1.VolatileTime{Inner: v1.Now()},
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
}
if bs.LatestImage == "" {
readyCondition.Status = corev1.ConditionFalse
readyCondition.Message = NoLatestImageMessage
readyCondition.Reason = NoLatestImageReason
}

bs.Status = corev1alpha1.Status{
Conditions: corev1alpha1.Conditions{
readyCondition,
{
Type: corev1alpha1.ConditionReady,
Type: ConditionUpToDate,
Status: corev1.ConditionFalse,
LastTransitionTime: corev1alpha1.VolatileTime{Inner: v1.Now()},
Reason: ReconcileFailedReason,
Message: err.Error(),
},
},
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/build/v1alpha2/builder_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type BuilderResource interface {
GetNamespace() string
BuildBuilderSpec() corev1alpha1.BuildBuilderSpec
Ready() bool
UpToDate() bool
BuildpackMetadata() corev1alpha1.BuildpackMetadataList
RunImage() string
GetKind() string
Expand Down
8 changes: 6 additions & 2 deletions pkg/apis/build/v1alpha2/builder_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ import (
)

const (
BuilderKind = "Builder"
BuilderCRName = "builders.kpack.io"
BuilderKind = "Builder"
BuilderCRName = "builders.kpack.io"
ConditionUpToDate corev1alpha1.ConditionType = "UpToDate"
NoLatestImageReason string = "NoLatestImage"
NoLatestImageMessage string = "Builder has no latestImage"
ReconcileFailedReason string = "ReconcileFailed"
)

// +genclient
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/build/v1alpha2/image_builds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) {

type TestBuilderResource struct {
BuilderReady bool
BuilderUpToDate bool
BuilderMetadata []corev1alpha1.BuildpackMetadata
ImagePullSecrets []corev1.LocalObjectReference
Kind string
Expand All @@ -396,6 +397,10 @@ func (t TestBuilderResource) Ready() bool {
return t.BuilderReady
}

func (t TestBuilderResource) UpToDate() bool {
return t.BuilderUpToDate
}

func (t TestBuilderResource) BuildpackMetadata() corev1alpha1.BuildpackMetadataList {
return t.BuilderMetadata
}
Expand Down
8 changes: 5 additions & 3 deletions pkg/apis/build/v1alpha2/image_lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import (
)

const (
BuilderNotFound = "BuilderNotFound"
BuilderNotReady = "BuilderNotReady"
BuilderReady = "BuilderReady"
BuilderNotFound = "BuilderNotFound"
BuilderNotReady = "BuilderNotReady"
BuilderReady = "BuilderReady"
BuilderNotUpToDate = "BuilderNotUpToDate"
BuilderUpToDate = "BuilderUpToDate"
)

func (im *Image) BuilderNotFound() corev1alpha1.Conditions {
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/build/v1alpha2/image_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,4 @@ func (i *Image) NamespacedName() types.NamespacedName {
}

const ConditionBuilderReady corev1alpha1.ConditionType = "BuilderReady"
const ConditionBuilderUpToDate corev1alpha1.ConditionType = "BuilderUpToDate"
5 changes: 5 additions & 0 deletions pkg/duckbuilder/duck_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ func (b *DuckBuilder) Ready() bool {
(b.Generation == b.Status.ObservedGeneration)
}

func (b *DuckBuilder) UpToDate() bool {
return b.Status.GetCondition(buildapi.ConditionUpToDate).IsTrue() &&
(b.Generation == b.Status.ObservedGeneration)
}

func (b *DuckBuilder) BuildBuilderSpec() corev1alpha1.BuildBuilderSpec {
return corev1alpha1.BuildBuilderSpec{
Image: b.Status.LatestImage,
Expand Down
33 changes: 33 additions & 0 deletions pkg/duckbuilder/duck_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func testDuckBuilder(t *testing.T, when spec.G, it spec.S) {
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionTrue,
},
},
},
BuilderMetadata: corev1alpha1.BuildpackMetadataList{
Expand Down Expand Up @@ -81,6 +85,35 @@ func testDuckBuilder(t *testing.T, when spec.G, it spec.S) {
})
})

when("UpToDate", func() {

it("ready when UpToDate condition is true", func() {
require.True(t, duckBuilder.UpToDate())
})

it("not ready without conditions", func() {
duckBuilder.Status.Conditions = nil

require.False(t, duckBuilder.UpToDate())
})

it("not ready when not ready", func() {
duckBuilder.Status.Conditions = corev1alpha1.Conditions{
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionFalse,
},
}

require.False(t, duckBuilder.UpToDate())
})

it("not UpToDate when generation does not match observed generation", func() {
duckBuilder.Generation = duckBuilder.Status.ObservedGeneration + 1

require.False(t, duckBuilder.UpToDate())
})
})
it("BuildBuilderSpec provides latest image and pull secrets", func() {
require.Equal(t, corev1alpha1.BuildBuilderSpec{
Image: "some/builder@sha256:12345678",
Expand Down
40 changes: 40 additions & 0 deletions pkg/reconciler/builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ func testBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionTrue,
},
},
},
BuilderMetadata: []corev1alpha1.BuildpackMetadata{
Expand Down Expand Up @@ -320,6 +324,10 @@ func testBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionTrue,
},
},
},
BuilderMetadata: []corev1alpha1.BuildpackMetadata{},
Expand Down Expand Up @@ -383,6 +391,10 @@ func testBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionTrue,
},
},
},
BuilderMetadata: []corev1alpha1.BuildpackMetadata{
Expand Down Expand Up @@ -436,6 +448,13 @@ func testBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
{
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionFalse,
Reason: buildapi.NoLatestImageReason,
Message: buildapi.NoLatestImageMessage,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionFalse,
Reason: buildapi.ReconcileFailedReason,
Message: "create error",
},
},
Expand Down Expand Up @@ -491,6 +510,13 @@ func testBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
{
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionFalse,
Reason: buildapi.NoLatestImageReason,
Message: buildapi.NoLatestImageMessage,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionFalse,
Reason: buildapi.ReconcileFailedReason,
Message: "Error: clusterstack 'some-stack' is not ready",
},
},
Expand Down Expand Up @@ -526,6 +552,13 @@ func testBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
{
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionFalse,
Reason: buildapi.NoLatestImageReason,
Message: buildapi.NoLatestImageMessage,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionFalse,
Reason: buildapi.ReconcileFailedReason,
Message: `clusterstore.kpack.io "some-store" not found`,
},
},
Expand Down Expand Up @@ -561,6 +594,13 @@ func testBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
{
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionFalse,
Reason: buildapi.NoLatestImageReason,
Message: buildapi.NoLatestImageMessage,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionFalse,
Reason: buildapi.ReconcileFailedReason,
Message: `clusterstack.kpack.io "some-stack" not found`,
},
},
Expand Down
41 changes: 40 additions & 1 deletion pkg/reconciler/clusterbuilder/clusterbuilder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ func testClusterBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
APIVersion: "kpack.io/v1alpha2",
},
}

builder := &buildapi.ClusterBuilder{
ObjectMeta: metav1.ObjectMeta{
Name: builderName,
Expand Down Expand Up @@ -233,6 +232,10 @@ func testClusterBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionTrue,
},
},
},
BuilderMetadata: []corev1alpha1.BuildpackMetadata{
Expand Down Expand Up @@ -308,6 +311,10 @@ func testClusterBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionTrue,
},
},
},
BuilderMetadata: []corev1alpha1.BuildpackMetadata{},
Expand Down Expand Up @@ -363,6 +370,10 @@ func testClusterBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionTrue,
},
},
},
BuilderMetadata: []corev1alpha1.BuildpackMetadata{
Expand Down Expand Up @@ -405,7 +416,14 @@ func testClusterBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
{
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionFalse,
Message: buildapi.NoLatestImageMessage,
Reason: buildapi.NoLatestImageReason,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionFalse,
Message: "create error",
Reason: buildapi.ReconcileFailedReason,
},
},
},
Expand Down Expand Up @@ -472,7 +490,14 @@ func testClusterBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
{
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionFalse,
Message: buildapi.NoLatestImageMessage,
Reason: buildapi.NoLatestImageReason,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionFalse,
Message: "stack some-stack is not ready",
Reason: buildapi.ReconcileFailedReason,
},
},
},
Expand Down Expand Up @@ -510,6 +535,13 @@ func testClusterBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
{
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionFalse,
Message: buildapi.NoLatestImageMessage,
Reason: buildapi.NoLatestImageReason,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionFalse,
Reason: buildapi.ReconcileFailedReason,
Message: `clusterstore.kpack.io "some-store" not found`,
},
},
Expand Down Expand Up @@ -548,6 +580,13 @@ func testClusterBuilderReconciler(t *testing.T, when spec.G, it spec.S) {
{
Type: corev1alpha1.ConditionReady,
Status: corev1.ConditionFalse,
Message: buildapi.NoLatestImageMessage,
Reason: buildapi.NoLatestImageReason,
},
{
Type: buildapi.ConditionUpToDate,
Status: corev1.ConditionFalse,
Reason: buildapi.ReconcileFailedReason,
Message: `clusterstack.kpack.io "some-stack" not found`,
},
},
Expand Down
Loading