Skip to content
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
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ require (
gotest.tools v2.2.0+incompatible
gotest.tools/v3 v3.0.3
k8s.io/api v0.21.4
k8s.io/apiextensions-apiserver v0.21.4
k8s.io/apimachinery v0.21.4
k8s.io/client-go v0.21.4
k8s.io/code-generator v0.21.4
Expand Down
146 changes: 83 additions & 63 deletions pkg/apis/operator/v1alpha1/tektonaddon_lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,105 +22,125 @@ import (
)

var (
_ TektonComponentStatus = (*TektonAddonStatus)(nil)
addonsCondSet = apis.NewLivingConditionSet(
addonsCondSet = apis.NewLivingConditionSet(
DependenciesInstalled,
DeploymentsAvailable,
InstallSucceeded,
PreReconciler,
InstallerSetReady,
PostReconciler,
)
)

// GroupVersionKind returns SchemeGroupVersion of a TektonAddon
func (tp *TektonAddon) GroupVersionKind() schema.GroupVersionKind {
return SchemeGroupVersion.WithKind(KindTektonAddon)
}

// GetCondition returns the current condition of a given condition type
func (tps *TektonAddonStatus) GetCondition(t apis.ConditionType) *apis.Condition {
return addonsCondSet.Manage(tps).GetCondition(t)
func (tp *TektonAddon) GetGroupVersionKind() schema.GroupVersionKind {
return SchemeGroupVersion.WithKind(KindTektonAddon)
}

func (tas *TektonAddonStatus) GetCondition(t apis.ConditionType) *apis.Condition {
return addonsCondSet.Manage(tas).GetCondition(t)
}

func (tas *TektonAddonStatus) InitializeConditions() {
addonsCondSet.Manage(tas).InitializeConditions()
}

// InitializeConditions initializes conditions of an TektonAddonStatus
func (tps *TektonAddonStatus) InitializeConditions() {
addonsCondSet.Manage(tps).InitializeConditions()
func (tas *TektonAddonStatus) IsReady() bool {
return addonsCondSet.Manage(tas).IsHappy()
}

// IsReady looks at the conditions returns true if they are all true.
func (tps *TektonAddonStatus) IsReady() bool {
return addonsCondSet.Manage(tps).IsHappy()
func (tas *TektonAddonStatus) MarkPreReconcilerComplete() {
addonsCondSet.Manage(tas).MarkTrue(PreReconciler)
}

// MarkInstallSucceeded marks the InstallationSucceeded status as true.
func (tps *TektonAddonStatus) MarkInstallSucceeded() {
addonsCondSet.Manage(tps).MarkTrue(InstallSucceeded)
if tps.GetCondition(DependenciesInstalled).IsUnknown() {
// Assume deps are installed if we're not sure
tps.MarkDependenciesInstalled()
}
func (tas *TektonAddonStatus) MarkInstallerSetReady() {
addonsCondSet.Manage(tas).MarkTrue(InstallerSetReady)
}

// MarkInstallFailed marks the InstallationSucceeded status as false with the given
// message.
func (tps *TektonAddonStatus) MarkInstallFailed(msg string) {
addonsCondSet.Manage(tps).MarkFalse(
InstallSucceeded,
func (tas *TektonAddonStatus) MarkPostReconcilerComplete() {
addonsCondSet.Manage(tas).MarkTrue(PostReconciler)
}

func (tas *TektonAddonStatus) MarkDependenciesInstalled() {
addonsCondSet.Manage(tas).MarkTrue(DependenciesInstalled)
}

func (tas *TektonAddonStatus) MarkNotReady(msg string) {
addonsCondSet.Manage(tas).MarkFalse(
apis.ConditionReady,
"Error",
"Install failed with message: %s", msg)
"Ready: %s", msg)
}

// MarkDeploymentsAvailable marks the DeploymentsAvailable status as true.
func (tps *TektonAddonStatus) MarkDeploymentsAvailable() {
addonsCondSet.Manage(tps).MarkTrue(DeploymentsAvailable)
func (tas *TektonAddonStatus) MarkPreReconcilerFailed(msg string) {
tas.MarkNotReady("PreReconciliation failed")
addonsCondSet.Manage(tas).MarkFalse(
PreReconciler,
"Error",
"PreReconciliation failed with message: %s", msg)
}

// MarkDeploymentsNotReady marks the DeploymentsAvailable status as false and calls out
// it's waiting for deployments.
func (tps *TektonAddonStatus) MarkDeploymentsNotReady() {
addonsCondSet.Manage(tps).MarkFalse(
DeploymentsAvailable,
"NotReady",
"Waiting on deployments")
func (tas *TektonAddonStatus) MarkInstallerSetNotReady(msg string) {
tas.MarkNotReady("TektonInstallerSet not ready")
addonsCondSet.Manage(tas).MarkFalse(
InstallerSetReady,
"Error",
"Installer set not ready: %s", msg)
}

// MarkDependenciesInstalled marks the DependenciesInstalled status as true.
func (tps *TektonAddonStatus) MarkDependenciesInstalled() {
addonsCondSet.Manage(tps).MarkTrue(DependenciesInstalled)
func (tas *TektonAddonStatus) MarkPostReconcilerFailed(msg string) {
tas.MarkNotReady("PostReconciliation failed")
addonsCondSet.Manage(tas).MarkFalse(
PostReconciler,
"Error",
"PostReconciliation failed with message: %s", msg)
}

// MarkDependencyInstalling marks the DependenciesInstalled status as false with the
// given message.
func (tps *TektonAddonStatus) MarkDependencyInstalling(msg string) {
addonsCondSet.Manage(tps).MarkFalse(
func (tas *TektonAddonStatus) MarkDependencyInstalling(msg string) {
tas.MarkNotReady("Dependencies installing")
addonsCondSet.Manage(tas).MarkFalse(
DependenciesInstalled,
"Installing",
"Dependency installing: %s", msg)
"Error",
"Dependencies are installing: %s", msg)
}

// MarkDependencyMissing marks the DependenciesInstalled status as false with the
// given message.
func (tps *TektonAddonStatus) MarkDependencyMissing(msg string) {
addonsCondSet.Manage(tps).MarkFalse(
func (tas *TektonAddonStatus) MarkDependencyMissing(msg string) {
tas.MarkNotReady("Missing Dependencies for TektonTriggers")
addonsCondSet.Manage(tas).MarkFalse(
DependenciesInstalled,
"Error",
"Dependency missing: %s", msg)
"Dependencies are missing: %s", msg)
}

func (tas *TektonAddonStatus) GetVersion() string {
return tas.Version
}

func (tas *TektonAddonStatus) SetVersion(version string) {
tas.Version = version
}

// TODO: below methods are not required for TektonAddon
// but as extension implements TektonComponent we need to define them
// this will be removed

func (tas *TektonAddonStatus) MarkInstallSucceeded() {
panic("implement me")
}

// GetVersion gets the currently installed version of the component.
func (tps *TektonAddonStatus) GetVersion() string {
return tps.Version
func (tas *TektonAddonStatus) MarkInstallFailed(msg string) {
panic("implement me")
}

// SetVersion sets the currently installed version of the component.
func (tps *TektonAddonStatus) SetVersion(version string) {
tps.Version = version
func (tas *TektonAddonStatus) MarkDeploymentsAvailable() {
panic("implement me")
}

// GetManifests gets the url links of the manifests.
func (tps *TektonAddonStatus) GetManifests() []string {
return tps.Manifests
func (tas *TektonAddonStatus) MarkDeploymentsNotReady() {
panic("implement me")
}

// SetVersion sets the url links of the manifests.
func (tps *TektonAddonStatus) SetManifests(manifests []string) {
tps.Manifests = manifests
func (tas *TektonAddonStatus) GetManifests() []string {
panic("implement me")
}
150 changes: 61 additions & 89 deletions pkg/apis/operator/v1alpha1/tektonaddon_lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,109 +30,81 @@ func TestTektonAddonGroupVersionKind(t *testing.T) {
Version: SchemaVersion,
Kind: KindTektonAddon,
}
if got := r.GroupVersionKind(); got != want {
if got := r.GetGroupVersionKind(); got != want {
t.Errorf("got: %v, want: %v", got, want)
}
}

func TestTektonAddonHappyPath(t *testing.T) {
tt := &TektonAddonStatus{}
tt.InitializeConditions()

apistest.CheckConditionOngoing(tt, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tt, DeploymentsAvailable, t)
apistest.CheckConditionOngoing(tt, InstallSucceeded, t)

// Install succeeds.
tt.MarkInstallSucceeded()
// Dependencies are assumed successful too.
apistest.CheckConditionSucceeded(tt, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tt, DeploymentsAvailable, t)
apistest.CheckConditionSucceeded(tt, InstallSucceeded, t)

// Deployments are not available at first.
tt.MarkDeploymentsNotReady()
apistest.CheckConditionSucceeded(tt, DependenciesInstalled, t)
apistest.CheckConditionFailed(tt, DeploymentsAvailable, t)
apistest.CheckConditionSucceeded(tt, InstallSucceeded, t)
if ready := tt.IsReady(); ready {
t.Errorf("tt.IsReady() = %v, want false", ready)
}
tr := &TektonAddonStatus{}
tr.InitializeConditions()

apistest.CheckConditionOngoing(tr, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tr, PreReconciler, t)
apistest.CheckConditionOngoing(tr, InstallerSetReady, t)
apistest.CheckConditionOngoing(tr, PostReconciler, t)

// Dependencies installed
tr.MarkDependenciesInstalled()
apistest.CheckConditionSucceeded(tr, DependenciesInstalled, t)

// Pre reconciler completes execution
tr.MarkPreReconcilerComplete()
apistest.CheckConditionSucceeded(tr, PreReconciler, t)

// Deployments become ready and we're good.
tt.MarkDeploymentsAvailable()
apistest.CheckConditionSucceeded(tt, DependenciesInstalled, t)
apistest.CheckConditionSucceeded(tt, DeploymentsAvailable, t)
apistest.CheckConditionSucceeded(tt, InstallSucceeded, t)
if ready := tt.IsReady(); !ready {
t.Errorf("tt.IsReady() = %v, want true", ready)
tr.MarkInstallerSetNotReady("waiting for resources to get installed")
apistest.CheckConditionFailed(tr, InstallerSetReady, t)

// InstallerSet and then PostReconciler become ready and we're good.
tr.MarkInstallerSetReady()
apistest.CheckConditionSucceeded(tr, InstallerSetReady, t)

tr.MarkPostReconcilerComplete()
apistest.CheckConditionSucceeded(tr, PostReconciler, t)

if ready := tr.IsReady(); !ready {
t.Errorf("tr.IsReady() = %v, want true", ready)
}
}

func TestTektonAddonErrorPath(t *testing.T) {
tt := &TektonAddonStatus{}
tt.InitializeConditions()

apistest.CheckConditionOngoing(tt, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tt, DeploymentsAvailable, t)
apistest.CheckConditionOngoing(tt, InstallSucceeded, t)

// Install fails.
tt.MarkInstallFailed("test")
apistest.CheckConditionOngoing(tt, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tt, DeploymentsAvailable, t)
apistest.CheckConditionFailed(tt, InstallSucceeded, t)

// Dependencies are installing.
tt.MarkDependencyInstalling("testing")
apistest.CheckConditionFailed(tt, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tt, DeploymentsAvailable, t)
apistest.CheckConditionFailed(tt, InstallSucceeded, t)

// Install now succeeds.
tt.MarkInstallSucceeded()
apistest.CheckConditionFailed(tt, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tt, DeploymentsAvailable, t)
apistest.CheckConditionSucceeded(tt, InstallSucceeded, t)
if ready := tt.IsReady(); ready {
t.Errorf("tt.IsReady() = %v, want false", ready)
}
tr := &TektonAddonStatus{}
tr.InitializeConditions()

// Deployments become ready
tt.MarkDeploymentsAvailable()
apistest.CheckConditionFailed(tt, DependenciesInstalled, t)
apistest.CheckConditionSucceeded(tt, DeploymentsAvailable, t)
apistest.CheckConditionSucceeded(tt, InstallSucceeded, t)
if ready := tt.IsReady(); ready {
t.Errorf("tt.IsReady() = %v, want false", ready)
}
apistest.CheckConditionOngoing(tr, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tr, PreReconciler, t)
apistest.CheckConditionOngoing(tr, InstallerSetReady, t)
apistest.CheckConditionOngoing(tr, PostReconciler, t)

// Finally, dependencies become available.
tt.MarkDependenciesInstalled()
apistest.CheckConditionSucceeded(tt, DependenciesInstalled, t)
apistest.CheckConditionSucceeded(tt, DeploymentsAvailable, t)
apistest.CheckConditionSucceeded(tt, InstallSucceeded, t)
if ready := tt.IsReady(); !ready {
t.Errorf("tt.IsReady() = %v, want true", ready)
}
}
// Dependencies installed
tr.MarkDependenciesInstalled()
apistest.CheckConditionSucceeded(tr, DependenciesInstalled, t)

// Pre reconciler completes execution
tr.MarkPreReconcilerComplete()
apistest.CheckConditionSucceeded(tr, PreReconciler, t)

func TestTektonAddonExternalDependency(t *testing.T) {
tt := &TektonAddonStatus{}
tt.InitializeConditions()
// InstallerSet is not ready when resources are not installed
tr.MarkInstallerSetNotReady("waiting for resources to get installed")
apistest.CheckConditionFailed(tr, InstallerSetReady, t)

// External marks dependency as failed.
tt.MarkDependencyMissing("test")
// InstallerSet and then PostReconciler become ready and we're good.
tr.MarkInstallerSetReady()
apistest.CheckConditionSucceeded(tr, InstallerSetReady, t)

// Install succeeds.
tt.MarkInstallSucceeded()
apistest.CheckConditionFailed(tt, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tt, DeploymentsAvailable, t)
apistest.CheckConditionSucceeded(tt, InstallSucceeded, t)
tr.MarkPostReconcilerComplete()
apistest.CheckConditionSucceeded(tr, PostReconciler, t)

// Dependencies are now ready.
tt.MarkDependenciesInstalled()
apistest.CheckConditionSucceeded(tt, DependenciesInstalled, t)
apistest.CheckConditionOngoing(tt, DeploymentsAvailable, t)
apistest.CheckConditionSucceeded(tt, InstallSucceeded, t)
if ready := tr.IsReady(); !ready {
t.Errorf("tr.IsReady() = %v, want true", ready)
}

// In further reconciliation while installing are resource might fail and installer
// set will change to not ready

tr.MarkInstallerSetNotReady("webhook not ready")
apistest.CheckConditionFailed(tr, InstallerSetReady, t)
if ready := tr.IsReady(); ready {
t.Errorf("tr.IsReady() = %v, want false", ready)
}
}
9 changes: 2 additions & 7 deletions pkg/apis/operator/v1alpha1/tektonaddon_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ import (
duckv1 "knative.dev/pkg/apis/duck/v1"
)

var (
_ TektonComponent = (*TektonAddon)(nil)
_ TektonComponentSpec = (*TektonAddonSpec)(nil)
)

// TektonAddon is the Schema for the tektonaddons API
// +genclient
// +genreconciler:krshapedlogic=false
Expand Down Expand Up @@ -65,9 +60,9 @@ type TektonAddonStatus struct {
// +optional
Version string `json:"version,omitempty"`

// The url links of the manifests, separated by comma
// TektonInstallerSet created to install addons
// +optional
Manifests []string `json:"manifests,omitempty"`
AddonsInstallerSet map[string]string `json:"installerSets,omitempty"`
}

// TektonAddonsList contains a list of TektonAddon
Expand Down
Loading