Skip to content

Commit

Permalink
Simplify version checks in back end
Browse files Browse the repository at this point in the history
Simplify the back end code that's used to get the version of the
installed Tekton projects in the cluster for display on the About
page. Also remove the `IsOpenShift` flag as it no longer provides
any value.

All supported versions have standardised on the set of labels
present on deployments, including both the project name and version.

This is common to manual and operator installs. Tested with the
following operator installs:
- OpenShift Pipelines Operator on CRC 1.24 (OpenShift 4.7.2)
- Tekton Operator v0.22.0-1 on kind (kubernetes 1.20.2)
  • Loading branch information
AlanGreene authored and tekton-robot committed Apr 9, 2021
1 parent 1f884de commit c0e5a4f
Show file tree
Hide file tree
Showing 25 changed files with 24 additions and 210 deletions.
2 changes: 0 additions & 2 deletions cmd/dashboard/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ var (
kubeConfigPath = flag.String("kube-config", "", "Path to kube config file")
portNumber = flag.Int("port", 8080, "Dashboard port number")
readOnly = flag.Bool("read-only", false, "Enable or disable read only mode")
isOpenshift = flag.Bool("openshift", false, "Indicates the dashboard is running on openshift")
logoutUrl = flag.String("logout-url", "", "If set, enables logout on the frontend and binds the logout button to this url")
tenantNamespace = flag.String("namespace", "", "If set, limits the scope of resources watched to this namespace only")
logLevel = flag.String("log-level", "info", "Minimum log level output by the logger")
Expand Down Expand Up @@ -107,7 +106,6 @@ func main() {
TriggersNamespace: *triggersNamespace,
TenantNamespace: *tenantNamespace,
ReadOnly: *readOnly,
IsOpenShift: *isOpenshift,
LogoutURL: *logoutUrl,
StreamLogs: *streamLogs,
ExternalLogsURL: *externalLogs,
Expand Down
1 change: 0 additions & 1 deletion docs/dev/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ Example payload response is formatted as so:
"PipelineVersion": "v0.10.0",
"TriggersNamespace": "tekton-pipelines",
"TriggersVersion": "v0.3.1",
"IsOpenShift": false,
"ReadOnly": true
}
```
4 changes: 0 additions & 4 deletions overlays/patches/installer/deployment-patch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@
path: /spec/template/spec/containers/0/args/-
value:
--namespace=--tenant-namespace
- op: add
path: /spec/template/spec/containers/0/args/-
value:
--openshift=--openshift
- op: add
path: /spec/template/spec/containers/0/args/-
value:
Expand Down
6 changes: 2 additions & 4 deletions pkg/endpoints/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ type Properties struct {
PipelineVersion string `json:"PipelineVersion"`
TriggersNamespace string `json:"TriggersNamespace,omitempty"`
TriggersVersion string `json:"TriggersVersion,omitempty"`
IsOpenShift bool `json:"IsOpenShift"`
ReadOnly bool `json:"ReadOnly"`
LogoutURL string `json:"LogoutURL,omitempty"`
TenantNamespace string `json:"TenantNamespace,omitempty"`
Expand All @@ -56,8 +55,8 @@ func (r Resource) ProxyRequest(request *restful.Request, response *restful.Respo
}

// GetProperties is used to get the installed namespace for the Dashboard,
// the version of the Tekton Dashboard, the version of Tekton Pipelines, whether or not one's
// running on OpenShift, when one's in read-only mode and Tekton Triggers version (if Installed)
// the version of the Tekton Dashboard, the version of Tekton Pipelines,
// when one's in read-only mode and Tekton Triggers version (if Installed)
func (r Resource) GetProperties(request *restful.Request, response *restful.Response) {
pipelineNamespace := r.Options.GetPipelinesNamespace()
triggersNamespace := r.Options.GetTriggersNamespace()
Expand All @@ -69,7 +68,6 @@ func (r Resource) GetProperties(request *restful.Request, response *restful.Resp
DashboardVersion: dashboardVersion,
PipelineNamespace: pipelineNamespace,
PipelineVersion: pipelineVersion,
IsOpenShift: r.Options.IsOpenShift,
ReadOnly: r.Options.ReadOnly,
LogoutURL: r.Options.LogoutURL,
TenantNamespace: r.Options.TenantNamespace,
Expand Down
162 changes: 20 additions & 142 deletions pkg/endpoints/dashboard.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 The Tekton Authors
Copyright 2020-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
Expand All @@ -15,189 +15,67 @@ package endpoints

import (
"context"
"strings"

"github.com/tektoncd/dashboard/pkg/logging"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Get dashboard version
func getDashboardVersion(r Resource, installedNamespace string) string {
// Get installed version of the requested Tekton project
func getVersion(r Resource, projectName string, namespace string) string {
version := ""

listOptions := metav1.ListOptions{
LabelSelector: "app=tekton-dashboard",
LabelSelector: "app.kubernetes.io/part-of=tekton-" + projectName,
}
deployments, err := r.K8sClient.AppsV1().Deployments(installedNamespace).List(context.TODO(), listOptions)
deployments, err := r.K8sClient.AppsV1().Deployments(namespace).List(context.TODO(), listOptions)
if err != nil {
logging.Log.Errorf("Error getting dashboard deployment: %s", err.Error())
logging.Log.Errorf("Error getting the Tekton %s deployment: %s", projectName, err.Error())
return ""
}

for _, deployment := range deployments.Items {
deploymentLabels := deployment.GetLabels()
versionAttempt, err := deploymentLabels["version"]
if err != true {
logging.Log.Error("Error getting dashboard version from yaml")
return ""
} else {
version = versionAttempt

version = deploymentLabels["app.kubernetes.io/version"]
if version != "" {
return version
}
}

if version == "" {
logging.Log.Error("Error getting the tekton dashboard deployment version. Version is unknown")
return ""
}
return version
}

// Get pipelines version
func getPipelineVersion(r Resource, namespace string) string {
version := getDeployments(r, "pipelines", namespace)
func getDashboardVersion(r Resource, namespace string) string {
version := getVersion(r, "dashboard", namespace)

if version == "" {
logging.Log.Error("Error getting the Tekton Pipelines deployment version. Version is unknown")
logging.Log.Error("Error getting the Tekton Dashboard deployment version. Version is unknown")
}

return version
}

// Get Deployments for either Tekton Triggers or Tekton Pipelines and gets the version
func getDeployments(r Resource, thingSearchingFor string, namespace string) string {
version := ""

oldListOptions := metav1.ListOptions{
LabelSelector: "app.kubernetes.io/component=controller,app.kubernetes.io/name=tekton-" + thingSearchingFor,
}
oldDeployments, err := r.K8sClient.AppsV1().Deployments(namespace).List(context.TODO(), oldListOptions)
if err != nil {
logging.Log.Errorf("Error getting the Tekton %s deployment: %s", thingSearchingFor, err.Error())
return ""
}
newListOptions := metav1.ListOptions{
LabelSelector: "app.kubernetes.io/component=controller,app.kubernetes.io/name=controller,app.kubernetes.io/part-of=tekton-" + thingSearchingFor,
}
newDeployments, err := r.K8sClient.AppsV1().Deployments(namespace).List(context.TODO(), newListOptions)
if err != nil {
logging.Log.Errorf("Error getting the Tekton %s deployment: %s", thingSearchingFor, err.Error())
return ""
}

deployments := append(oldDeployments.Items, newDeployments.Items...)

for _, deployment := range deployments {
deploymentLabels := deployment.GetLabels()

if version == "" {
version = deploymentLabels[thingSearchingFor+".tekton.dev/release"]
}

if version == "" {
version = deploymentLabels["version"]
}

// Installs through the OpenShift Operator displays version differently
// This deals with the OpenShift Operator install
if version == "" {
deploymentImage := deployment.Spec.Template.Spec.Containers[0].Image
if strings.Contains(deploymentImage, "openshift-pipeline/tektoncd-"+thingSearchingFor+"-controller") && strings.Contains(deploymentImage, ":") {
s := strings.SplitAfter(deploymentImage, ":")
if s[1] != "" {
version = s[1]
}
}
}
}
func getPipelineVersion(r Resource, namespace string) string {
version := getVersion(r, "pipelines", namespace)

if version == "" && thingSearchingFor == "pipelines" {
for _, deployment := range deployments {
deploymentLabels := deployment.GetLabels()
labelsToCheck := []string{"pipeline.tekton.dev/release", "version"} // To handle both beta and pre-beta versions
for _, label := range labelsToCheck {
potentialVersion := deploymentLabels[label]
if potentialVersion != "" {
version = potentialVersion
}
}

deploymentImage := deployment.Spec.Template.Spec.Containers[0].Image
if strings.Contains(deploymentImage, "openshift-pipeline/tektoncd-pipeline-controller") && strings.Contains(deploymentImage, ":") {
s := strings.SplitAfter(deploymentImage, ":")
if s[1] != "" {
version = s[1]
}
}

deploymentAnnotations := deployment.Spec.Template.GetAnnotations()
annotationsToCheck := []string{"pipeline.tekton.dev/release", "tekton.dev/release"} // To handle 0.10.0 and 0.10.1
for _, label := range annotationsToCheck {
potentialVersion := deploymentAnnotations[label]
if potentialVersion != "" {
version = potentialVersion
}
}

// For Tekton Pipelines 0.9.0 - 0.9.2
if version == "" {
deploymentImage := deployment.Spec.Template.Spec.Containers[0].Image
if strings.Contains(deploymentImage, "pipeline/cmd/controller") && strings.Contains(deploymentImage, ":") && strings.Contains(deploymentImage, "@") {
s := strings.SplitAfter(deploymentImage, ":")
if strings.Contains(s[1], "@") {
t := strings.Split(s[1], "@")
version = t[0]
}
}
}
}
if version == "" {
logging.Log.Error("Error getting the Tekton Pipelines deployment version. Version is unknown")
}

return version
}

// Get triggers version
func getTriggersVersion(r Resource, namespace string) string {
version := getDeployments(r, "triggers", namespace)
version := getVersion(r, "triggers", namespace)

if version == "" {
logging.Log.Error("Error getting the Tekton Triggers deployment version. Version is unknown")
version = "UNKNOWN"
}

return version
}

// Check whether Tekton Triggers is installed
func IsTriggersInstalled(r Resource, namespace string) bool {
return searchForDeployment(r, "triggers", namespace)
}

// Go through Triggers deployments and find if it is installed
func searchForDeployment(r Resource, thingSearchingFor string, namespace string) bool {
oldListOptions := metav1.ListOptions{
LabelSelector: "app.kubernetes.io/component=controller,app.kubernetes.io/name=tekton-" + thingSearchingFor,
}
oldDeployments, err := r.K8sClient.AppsV1().Deployments(namespace).List(context.TODO(), oldListOptions)
if err != nil {
logging.Log.Errorf("Error getting the Tekton %s deployment: %s", thingSearchingFor, err.Error())
return false
}
newListOptions := metav1.ListOptions{
LabelSelector: "app.kubernetes.io/component=controller,app.kubernetes.io/name=controller,app.kubernetes.io/part-of=tekton-" + thingSearchingFor,
}
newDeployments, err := r.K8sClient.AppsV1().Deployments(namespace).List(context.TODO(), newListOptions)
if err != nil {
logging.Log.Errorf("Error getting the Tekton %s deployment: %s", thingSearchingFor, err.Error())
return false
}

deployments := append(oldDeployments.Items, newDeployments.Items...)

for _, deployment := range deployments {
if deployment.GetName() == "tekton-"+thingSearchingFor+"-controller" {
return true
}
}

return false
version := getTriggersVersion(r, namespace)
return version != ""
}
1 change: 0 additions & 1 deletion pkg/endpoints/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ type Options struct {
TriggersNamespace string
TenantNamespace string
ReadOnly bool
IsOpenShift bool
LogoutURL string
StreamLogs bool
ExternalLogsURL string
Expand Down
1 change: 0 additions & 1 deletion scripts/installer
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ patch() {
replace "--logout-url=--logout-url" "--logout-url=$LOGOUT_URL"
replace "--read-only=--read-only" "--read-only=$READONLY"
replace "--namespace=--tenant-namespace" "--namespace=$TENANT_NAMESPACE"
replace "--openshift=--openshift" "--openshift=$OPENSHIFT"
replace "--stream-logs=--stream-logs" "--stream-logs=$STREAM_LOGS"
replace "--external-logs=--external-logs" "--external-logs=$EXTERNAL_LOGS"
replace "namespace: tekton-dashboard" "namespace: $INSTALL_NAMESPACE"
Expand Down
8 changes: 0 additions & 8 deletions src/containers/About/About.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import {
getPipelineVersion,
getTriggersNamespace,
getTriggersVersion,
isOpenShift as selectIsOpenShift,
isReadOnly as selectIsReadOnly,
isTriggersInstalled as selectIsTriggersInstalled
} from '../../reducers';
Expand All @@ -40,7 +39,6 @@ export function About({
dashboardNamespace,
dashboardVersion,
intl,
isOpenShift,
isReadOnly,
isTriggersInstalled,
logoutURL,
Expand Down Expand Up @@ -127,10 +125,6 @@ export function About({
id: 'dashboard.about.version',
defaultMessage: 'Version'
});
const isOpenShiftLabel = intl.formatMessage({
id: 'dashboard.about.isOpenShift',
defaultMessage: 'IsOpenShift'
});
const isReadOnlyLabel = intl.formatMessage({
id: 'dashboard.about.isReadOnly',
defaultMessage: 'ReadOnly'
Expand Down Expand Up @@ -167,7 +161,6 @@ export function About({
rows={[
getRow('Namespace', dashboardNamespace),
getRow(versionLabel, dashboardVersion),
getRow(isOpenShiftLabel, isOpenShift),
getRow(isReadOnlyLabel, isReadOnly),
getRow(logoutURLLabel, logoutURL)
].filter(Boolean)}
Expand Down Expand Up @@ -220,7 +213,6 @@ export function About({
const mapStateToProps = state => ({
dashboardNamespace: getDashboardNamespace(state),
dashboardVersion: getDashboardVersion(state),
isOpenShift: selectIsOpenShift(state),
isReadOnly: selectIsReadOnly(state),
isTriggersInstalled: selectIsTriggersInstalled(state),
logoutURL: getLogoutURL(state),
Expand Down
10 changes: 2 additions & 8 deletions src/containers/About/About.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 The Tekton Authors
Copyright 2020-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
Expand Down Expand Up @@ -35,7 +35,6 @@ describe('About', () => {
PipelineVersion: 'v0.10.0',
TriggersNamespace: 'tekton-triggers',
TriggersVersion: 'v0.3.1',
IsOpenShift: true,
ReadOnly: true
}
});
Expand All @@ -52,9 +51,8 @@ describe('About', () => {
expect(queryByText('tekton-dashboard', dashboardSelector)).toBeTruthy();
expect(queryByText('Version', dashboardSelector)).toBeTruthy();
expect(queryByText('v0.100.0', dashboardSelector)).toBeTruthy();
expect(queryByText('IsOpenShift', dashboardSelector)).toBeTruthy();
expect(queryByText('ReadOnly', dashboardSelector)).toBeTruthy();
expect(queryAllByText('True', dashboardSelector).length).toBe(2);
expect(queryAllByText('True', dashboardSelector).length).toBe(1);

expect(queryByText('Property', pipelinesSelector)).toBeTruthy();
expect(queryByText('Value', pipelinesSelector)).toBeTruthy();
Expand All @@ -78,7 +76,6 @@ describe('About', () => {
// DashboardVersion: '', this is intentionally missing
PipelineNamespace: 'tekton-pipelines',
PipelineVersion: 'v0.10.0',
IsOpenShift: false,
ReadOnly: false
}
});
Expand All @@ -94,7 +91,6 @@ describe('About', () => {
expect(queryByText('Namespace', dashboardSelector)).toBeTruthy();
expect(queryByText('tekton-dashboard', dashboardSelector)).toBeTruthy();
expect(queryByText('Version', dashboardSelector)).toBeFalsy();
expect(queryByText('IsOpenShift', dashboardSelector)).toBeFalsy();
expect(queryByText('ReadOnly', dashboardSelector)).toBeFalsy();

expect(queryByText('Property', pipelinesSelector)).toBeTruthy();
Expand Down Expand Up @@ -128,7 +124,6 @@ describe('About', () => {
expect(queryByText('Namespace', dashboardSelector)).toBeTruthy();
expect(queryByText('tekton-dashboard', dashboardSelector)).toBeTruthy();
expect(queryByText('Version', dashboardSelector)).toBeFalsy();
expect(queryByText('IsOpenShift', dashboardSelector)).toBeFalsy();
expect(queryByText('ReadOnly', dashboardSelector)).toBeFalsy();

expect(queryByText('Property', pipelinesSelector)).toBeTruthy();
Expand Down Expand Up @@ -166,7 +161,6 @@ describe('About', () => {
expect(queryByText('Namespace', dashboardSelector)).toBeTruthy();
expect(queryByText('tekton-dashboard', dashboardSelector)).toBeTruthy();
expect(queryByText('Version', dashboardSelector)).toBeTruthy();
expect(queryByText('IsOpenShift', dashboardSelector)).toBeFalsy();
expect(queryByText('ReadOnly', dashboardSelector)).toBeFalsy();

expect(queryByText('Property', pipelinesSelector)).toBeTruthy();
Expand Down
Loading

0 comments on commit c0e5a4f

Please sign in to comment.