Skip to content

Commit

Permalink
Adds TektonInstallerSet API
Browse files Browse the repository at this point in the history
This adds TektonInstaller which would install the manifest passed
in spec in a certain order defined, TektonPipeline/TektonTrigger and
other components will transform their manifest and pass to TektonInstallerSet
which will create the resources.
The components will create an tekton installer set and pass the manifest.
- while upgrading the version components can delete prev installer set
and create new one which will delete any obsolete resource removed in '
newer version.
- to change namespace of installed components, create a new installer set
and delete prev.

Deleting a installer will delete all resources except crds which would
not delete any user data.

Signed-off-by: Shivam Mukhade <[email protected]>
  • Loading branch information
Shivam Mukhade committed Sep 2, 2021
1 parent 2ed3f0d commit 7cf705e
Show file tree
Hide file tree
Showing 33 changed files with 2,517 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cmd/kubernetes/operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package main
import (
"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektonconfig"
"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektondashboard"
"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset"
"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektonpipeline"
"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektonresult"
"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektontrigger"
Expand All @@ -32,5 +33,6 @@ func main() {
tektondashboard.NewController,
tektonconfig.NewController,
tektonresult.NewController,
tektoninstallerset.NewController,
)
}
48 changes: 48 additions & 0 deletions config/base/300-operator_v1alpha1_installer_set_crd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2021 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: tektoninstallersets.operator.tekton.dev
labels:
version: "devel"
operator.tekton.dev/release: "devel"
spec:
group: operator.tekton.dev
names:
kind: TektonInstallerSet
listKind: TektonInstallerSetList
plural: tektoninstallersets
singular: tektoninstallerset
preserveUnknownFields: false
scope: Cluster
versions:
- name: v1alpha1
served: true
storage: true
subresources:
status: {}
additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=="Ready")].status
name: Ready
type: string
- jsonPath: ".status.conditions[?(@.type==\"Ready\")].reason"
name: Reason
type: string
schema:
openAPIV3Schema:
type: object
description: Schema for the tektoninstallerset API
x-kubernetes-preserve-unknown-fields: true
1 change: 1 addition & 0 deletions config/base/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ resources:
- 300-operator_v1alpha1_addon_crd.yaml
- 300-operator_v1alpha1_config_crd.yaml
- 300-operator_v1alpha1_result_crd.yaml
- 300-operator_v1alpha1_installer_set_crd.yaml
- 500-webhooks.yaml
- config-logging.yaml
- tekton-config-defaults.yaml
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module github.com/tektoncd/operator

require (
github.com/go-logr/logr v0.4.0
github.com/go-logr/zapr v0.4.0
github.com/google/go-cmp v0.5.5
github.com/manifestival/client-go-client v0.5.0
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/operator/v1alpha1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ const (

// KindTektonResult is the Kind of Tekton Config in a GVK context.
KindTektonResult = "TektonResult"

// KindTektonInstallerSet is the Kind of TektonInstallerSet in a GVK context.
KindTektonInstallerSet = "TektonInstallerSet"
)

// Resource takes an unqualified resource and returns a Group qualified GroupResource
Expand All @@ -69,6 +72,8 @@ func addKnownTypes(s *runtime.Scheme) error {
&TektonConfigList{},
&TektonResult{},
&TektonResultList{},
&TektonInstallerSet{},
&TektonInstallerSetList{},
)
metav1.AddToGroupVersion(s, SchemeGroupVersion)
return nil
Expand Down
141 changes: 141 additions & 0 deletions pkg/apis/operator/v1alpha1/tektoninstallerset_lifecycle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
"k8s.io/apimachinery/pkg/runtime/schema"
"knative.dev/pkg/apis"
)

const (
CrdInstalled apis.ConditionType = "CrdsInstalled"
ClustersScoped apis.ConditionType = "ClusterScopedResourcesInstalled"
NamespaceScoped apis.ConditionType = "NamespaceScopedResourcesInstalled"
DeploymentsAvailable apis.ConditionType = "DeploymentsAvailable"
WebhookReady apis.ConditionType = "WebhooksReady"
ControllerReady apis.ConditionType = "ControllersReady"
)

var (
installerSetCondSet = apis.NewLivingConditionSet(
CrdInstalled,
ClustersScoped,
NamespaceScoped,
DeploymentsAvailable,
WebhookReady,
ControllerReady,
)
)

func (tis *TektonInstallerSet) GetGroupVersionKind() schema.GroupVersionKind {
return SchemeGroupVersion.WithKind(KindTektonInstallerSet)
}

func (tis *TektonInstallerSetStatus) GetCondition(t apis.ConditionType) *apis.Condition {
return installerSetCondSet.Manage(tis).GetCondition(t)
}

func (tis *TektonInstallerSetStatus) InitializeConditions() {
installerSetCondSet.Manage(tis).InitializeConditions()
}

func (tis *TektonInstallerSetStatus) IsReady() bool {
return installerSetCondSet.Manage(tis).IsHappy()
}

func (tis *TektonInstallerSetStatus) MarkReady() {
installerSetCondSet.Manage(tis).MarkTrue(apis.ConditionReady)
}

func (tis *TektonInstallerSetStatus) MarkCRDsInstalled() {
installerSetCondSet.Manage(tis).MarkTrue(CrdInstalled)
}

func (tis *TektonInstallerSetStatus) MarkClustersScopedResourcesInstalled() {
installerSetCondSet.Manage(tis).MarkTrue(ClustersScoped)
}

func (tis *TektonInstallerSetStatus) MarkNamespaceScopedResourcesInstalled() {
installerSetCondSet.Manage(tis).MarkTrue(NamespaceScoped)
}

func (tis *TektonInstallerSetStatus) MarkDeploymentsAvailable() {
installerSetCondSet.Manage(tis).MarkTrue(DeploymentsAvailable)
}

func (tis *TektonInstallerSetStatus) MarkWebhookReady() {
installerSetCondSet.Manage(tis).MarkTrue(WebhookReady)
}

func (tis *TektonInstallerSetStatus) MarkControllerReady() {
installerSetCondSet.Manage(tis).MarkTrue(ControllerReady)
}

func (tis *TektonInstallerSetStatus) MarkNotReady(msg string) {
installerSetCondSet.Manage(tis).MarkFalse(
apis.ConditionReady,
"Error",
"Ready: %s", msg)
}

func (tis *TektonInstallerSetStatus) MarkCRDsInstallationFailed(msg string) {
tis.MarkNotReady("CRDs installation failed")
installerSetCondSet.Manage(tis).MarkFalse(
CrdInstalled,
"Error",
"Install failed with message: %s", msg)
}

func (tis *TektonInstallerSetStatus) MarkClustersScopedInstallationFailed(msg string) {
tis.MarkNotReady("Cluster Scoped resources installation failed")
installerSetCondSet.Manage(tis).MarkFalse(
ClustersScoped,
"Error",
"Install failed with message: %s", msg)
}

func (tis *TektonInstallerSetStatus) MarkNamespaceScopedInstallationFailed(msg string) {
tis.MarkNotReady("Namespace Scoped resources installation failed")
installerSetCondSet.Manage(tis).MarkFalse(
NamespaceScoped,
"Error",
"Install failed with message: %s", msg)
}

func (tis *TektonInstallerSetStatus) MarkDeploymentsAvailableFailed(msg string) {
tis.MarkNotReady("Deployment resources installation failed")
installerSetCondSet.Manage(tis).MarkFalse(
DeploymentsAvailable,
"Error",
"Install failed with message: %s", msg)
}

func (tis *TektonInstallerSetStatus) MarkWebhookNotReady(msg string) {
tis.MarkNotReady("Webhooks not available")
installerSetCondSet.Manage(tis).MarkFalse(
WebhookReady,
"Error",
"Webhook: %s", msg)
}

func (tis *TektonInstallerSetStatus) MarkControllerNotReady(msg string) {
tis.MarkNotReady("Controller Deployment not available")
installerSetCondSet.Manage(tis).MarkFalse(
ControllerReady,
"Error",
"Controller: %s", msg)
}
127 changes: 127 additions & 0 deletions pkg/apis/operator/v1alpha1/tektoninstallerset_lifecycle_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
Copyright 2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
"testing"

"k8s.io/apimachinery/pkg/runtime/schema"
apistest "knative.dev/pkg/apis/testing"
)

func TestTektonInstallerSetGroupVersionKind(t *testing.T) {
r := &TektonInstallerSet{}
want := schema.GroupVersionKind{
Group: GroupName,
Version: SchemaVersion,
Kind: KindTektonInstallerSet,
}
if got := r.GetGroupVersionKind(); got != want {
t.Errorf("got: %v, want: %v", got, want)
}
}

func TestTektonInstallerSetHappyPath(t *testing.T) {
tis := &TektonInstallerSetStatus{}
tis.InitializeConditions()

apistest.CheckConditionOngoing(tis, CrdInstalled, t)
apistest.CheckConditionOngoing(tis, ClustersScoped, t)
apistest.CheckConditionOngoing(tis, NamespaceScoped, t)
apistest.CheckConditionOngoing(tis, DeploymentsAvailable, t)
apistest.CheckConditionOngoing(tis, WebhookReady, t)
apistest.CheckConditionOngoing(tis, ControllerReady, t)

// Install succeeds.
tis.MarkCRDsInstalled()
apistest.CheckConditionSucceeded(tis, CrdInstalled, t)

tis.MarkClustersScopedResourcesInstalled()
apistest.CheckConditionSucceeded(tis, ClustersScoped, t)

tis.MarkNamespaceScopedResourcesInstalled()
apistest.CheckConditionSucceeded(tis, NamespaceScoped, t)

tis.MarkDeploymentsAvailable()
apistest.CheckConditionSucceeded(tis, DeploymentsAvailable, t)

// Initially Webhook will not be available
tis.MarkWebhookNotReady("waiting for pods")
apistest.CheckConditionFailed(tis, WebhookReady, t)

tis.MarkWebhookReady()
apistest.CheckConditionSucceeded(tis, WebhookReady, t)

tis.MarkControllerReady()
apistest.CheckConditionSucceeded(tis, ControllerReady, t)

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

func TestTektonInstallerSetErrorPath(t *testing.T) {
tis := &TektonInstallerSetStatus{}
tis.InitializeConditions()

apistest.CheckConditionOngoing(tis, CrdInstalled, t)
apistest.CheckConditionOngoing(tis, ClustersScoped, t)
apistest.CheckConditionOngoing(tis, NamespaceScoped, t)
apistest.CheckConditionOngoing(tis, DeploymentsAvailable, t)
apistest.CheckConditionOngoing(tis, WebhookReady, t)
apistest.CheckConditionOngoing(tis, ControllerReady, t)

// CrdsInstall succeeds
tis.MarkCRDsInstalled()
apistest.CheckConditionSucceeded(tis, CrdInstalled, t)

// ClustersScopedResources Install succeeds
tis.MarkClustersScopedResourcesInstalled()
apistest.CheckConditionSucceeded(tis, ClustersScoped, t)

// NamespaceScopedResources Install succeeds
tis.MarkNamespaceScopedResourcesInstalled()
apistest.CheckConditionSucceeded(tis, NamespaceScoped, t)

// DeploymentsAvailable succeeds
tis.MarkDeploymentsAvailable()
apistest.CheckConditionSucceeded(tis, DeploymentsAvailable, t)

// Initially Webhook will not be available
tis.MarkWebhookNotReady("waiting for pods")
apistest.CheckConditionFailed(tis, WebhookReady, t)

tis.MarkWebhookReady()
apistest.CheckConditionSucceeded(tis, WebhookReady, t)

tis.MarkControllerReady()
apistest.CheckConditionSucceeded(tis, ControllerReady, t)

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

// Now in further reconciliation some error occurred in any of the
// condition

tis.MarkCRDsInstallationFailed("failed due to some error")
apistest.CheckConditionFailed(tis, CrdInstalled, t)

if ready := tis.IsReady(); ready {
t.Errorf("tt.IsReady() = %v, want false", ready)
}
}
Loading

0 comments on commit 7cf705e

Please sign in to comment.