Skip to content

Commit

Permalink
Check Tekton EventListeners CRD version to use matching api
Browse files Browse the repository at this point in the history
  • Loading branch information
jerolimov committed Sep 16, 2020
1 parent b6ffd5a commit 2468828
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 9 deletions.
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
"@types/react-router-dom": "5.1.2",
"@types/react-transition-group": "2.x",
"@types/react-virtualized": "9.x",
"@types/semver": "^6.0.0",
"@types/webpack": "4.x",
"babel-loader": "^8.1.0",
"bootstrap-sass": "^3.3.7",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { k8sList } from '@console/internal/module/k8s';
import { ClusterServiceVersionKind } from '@console/operator-lifecycle-manager';
import { getPipelineOperatorVersion } from '../utils/pipeline-operator';

jest.mock('@console/internal/module/k8s', () => ({
k8sList: jest.fn(),
}));

beforeEach(() => {
jest.resetAllMocks();
});

const k8sListMock = k8sList as jest.Mock;

describe('getPipelineOperatorVersion', () => {
it('should fetch the ClusterServiceVersion from the api', async () => {
const csvs = [
{
metadata: { name: 'openshift-pipelines-operator.v1.0.1' },
status: { phase: 'Succeeded' },
} as ClusterServiceVersionKind,
];
k8sListMock.mockReturnValueOnce(Promise.resolve(csvs));

const version = await getPipelineOperatorVersion('unit-test');

expect(version.raw).toBe('1.0.1');
expect(version.major).toBe(1);
expect(version.minor).toBe(0);
expect(version.patch).toBe(1);
expect(k8sList).toHaveBeenCalledTimes(1);
});

it('should return the active ClusterServiceVersion if multiple returns', async () => {
const csvs = [
{
metadata: { name: 'openshift-pipelines-operator.v1.0.1' },
status: { phase: 'Succeeded' },
} as ClusterServiceVersionKind,
{
metadata: { name: 'openshift-pipelines-operator.v1.1.1' },
status: { phase: 'Pending' },
} as ClusterServiceVersionKind,
];
k8sListMock.mockReturnValueOnce(Promise.resolve(csvs));

const version = await getPipelineOperatorVersion('unit-test');

expect(version.raw).toBe('1.0.1');
expect(version.major).toBe(1);
expect(version.minor).toBe(0);
expect(version.patch).toBe(1);
expect(k8sList).toHaveBeenCalledTimes(1);
});

it('should fetch the latest (highest) ClusterServiceVersion from the api', async () => {
const csvs = [
{
metadata: { name: 'openshift-pipelines-operator.v1.0.1' },
status: { phase: 'Succeeded' },
} as ClusterServiceVersionKind,
{
metadata: { name: 'openshift-pipelines-operator.v10.11.12' },
status: { phase: 'Succeeded' },
} as ClusterServiceVersionKind,
{
metadata: { name: 'openshift-pipelines-operator.v1.1.1' },
status: { phase: 'Succeeded' },
} as ClusterServiceVersionKind,
];
k8sListMock.mockReturnValueOnce(Promise.resolve(csvs));

const version = await getPipelineOperatorVersion('unit-test');

expect(version.raw).toBe('10.11.12');
expect(version.major).toBe(10);
expect(version.minor).toBe(11);
expect(version.patch).toBe(12);
expect(k8sList).toHaveBeenCalledTimes(1);
});

it('should return null if there is no ClusterServiceVersion available', async () => {
k8sListMock.mockReturnValueOnce(Promise.resolve([]));
await expect(getPipelineOperatorVersion('unit-test')).resolves.toBe(null);
expect(k8sList).toHaveBeenCalledTimes(1);
});

it('should return null if there is no matching ClusterServiceVersion available', async () => {
const csvs = [
{
metadata: { name: 'another-operator.v1.1.1' },
status: { phase: 'Succeeded' },
} as ClusterServiceVersionKind,
{
metadata: { name: 'openshift-pipelines-operator.v1.1.1' },
status: { phase: 'Installing' },
} as ClusterServiceVersionKind,
];
k8sListMock.mockReturnValueOnce(Promise.resolve(csvs));
await expect(getPipelineOperatorVersion('unit-test')).resolves.toBe(null);
expect(k8sList).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { RouteModel } from '@console/internal/models';
import { EventListenerModel, TriggerTemplateModel } from '../../../../models';
import { Pipeline, PipelineRun } from '../../../../utils/pipeline-augment';
import { PIPELINE_SERVICE_ACCOUNT } from '../../const';
import { getPipelineOperatorVersion } from '../../utils/pipeline-operator';
import {
TriggerBindingKind,
EventListenerKind,
EventListenerKindBindingReference,
TriggerBindingKind,
TriggerTemplateKind,
TriggerTemplateKindParam,
} from '../../resource-types';
Expand All @@ -29,10 +31,30 @@ export const createTriggerTemplate = (
};
};

export const createEventListener = (
export const createEventListener = async (
namespace: string,
triggerBindings: TriggerBindingKind[],
triggerTemplate: TriggerTemplateKind,
): EventListenerKind => {
): Promise<EventListenerKind> => {
const pipelineOperatorVersion = await getPipelineOperatorVersion(namespace);

const mapTriggerBindings: (
triggerBinding: TriggerBindingKind,
) => EventListenerKindBindingReference = (triggerBinding: TriggerBindingKind) => {
// The Tekton CRD `EventListeners` before Tekton Triggers 0.5 requires a name
// instead of a ref here to link `TriggerBinding` or `ClusterTriggerBinding`.
if (pipelineOperatorVersion?.major === 1 && pipelineOperatorVersion?.minor === 0) {
return {
kind: triggerBinding.kind,
name: triggerBinding.metadata.name,
} as EventListenerKindBindingReference;
}
return {
kind: triggerBinding.kind,
ref: triggerBinding.metadata.name,
};
};

return {
apiVersion: apiVersionForModel(EventListenerModel),
kind: EventListenerModel.kind,
Expand All @@ -43,7 +65,7 @@ export const createEventListener = (
serviceAccountName: PIPELINE_SERVICE_ACCOUNT,
triggers: [
{
bindings: triggerBindings.map(({ kind, metadata: { name } }) => ({ kind, name })),
bindings: triggerBindings.map(mapTriggerBindings),
template: { name: triggerTemplate.metadata.name },
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ export const submitTrigger = async (
pipelineRun,
triggerTemplateParams,
);
const eventListener: EventListenerKind = createEventListener(
const eventListener: EventListenerKind = await createEventListener(
thisNamespace,
[triggerBinding.resource],
triggerTemplate,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,16 @@ export type TriggerTemplateKind = K8sResourceCommon & {
};

export type EventListenerKindBindingReference = {
// TriggerBinding / ClusterTriggerBinding name reference
name: string;
kind?: string;
// TriggerBinding / ClusterTriggerBinding reference
kind: string;
// Ref is used since Tekton Triggers 0.5 (part of OpenShift Pipeline Operator 1.1)
ref: string;
// We also support older operators, so need to show & save the old field as well.
// https://github.com/tektoncd/triggers/pull/603/files
// https://github.com/tektoncd/triggers/releases/tag/v0.5.0 and
// https://github.com/tektoncd/triggers/releases/tag/v0.6.0
/** @deprecated use ref instead */
name?: string;
};

export type EventListenerKindTrigger = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { compare, parse, SemVer } from 'semver';
import {
ClusterServiceVersionKind,
ClusterServiceVersionModel,
ClusterServiceVersionPhase,
} from '@console/operator-lifecycle-manager';
import { k8sList } from '@console/internal/module/k8s';

export const getPipelineOperatorVersion = async (namespace: string): Promise<SemVer | null> => {
const csvs: ClusterServiceVersionKind[] = await k8sList(ClusterServiceVersionModel, {
ns: namespace,
});
const matchingCSVs = csvs.filter(
(csv) =>
csv.metadata?.name?.startsWith('openshift-pipelines-operator') &&
csv.status?.phase === ClusterServiceVersionPhase.CSVPhaseSucceeded,
);
const versions = matchingCSVs
.map((csv) => parse(csv.metadata?.name?.replace(/^openshift-pipelines-operator.v?/, '')))
.filter(Boolean);
// Orders from small (oldest) to highest (newest) versions
versions.sort(compare);
if (versions.length > 0) {
return versions[versions.length - 1];
}
return null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ export const getEventListenerTriggerBindingNames = (
): ResourceModelLink[] =>
bindings?.map((binding) => ({
model: getResourceModelFromBindingKind(binding.kind),
name: binding.name,
// Ref is used since Tekton Triggers 0.5 (OpenShift Pipeline Operator 1.1)
// We keep the fallback to name here to support also OpenShift Pipeline Operator 1.0.
name: binding.ref || binding.name,
}));

export const getTriggerTemplatePipelineName = (triggerTemplate: TriggerTemplateKind): string => {
Expand Down
5 changes: 5 additions & 0 deletions frontend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2707,6 +2707,11 @@
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz#50a4755f8e33edacd9c406729e9b930d2451902a"
integrity sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA==

"@types/semver@^6.0.0":
version "6.2.2"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.2.2.tgz#5c27df09ca39e3c9beb4fae6b95f4d71426df0a9"
integrity sha512-RxAwYt4rGwK5GyoRwuP0jT6ZHAVTdz2EqgsHmX0PYNjGsko+OeT4WFXXTs/lM3teJUJodM+SNtAL5/pXIJ61IQ==

"@types/shallowequal@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/shallowequal/-/shallowequal-1.1.1.tgz#aad262bb3f2b1257d94c71d545268d592575c9b1"
Expand Down

0 comments on commit 2468828

Please sign in to comment.