Skip to content

Commit d93c3e3

Browse files
Merge pull request #167 from alanconway/event-regression
COO-1178: Fix regression in linkToQuery for events.
2 parents af90c0d + 6bddd67 commit d93c3e3

2 files changed

Lines changed: 47 additions & 17 deletions

File tree

web/src/__tests__/k8s.spec.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,6 @@ describe('K8sDomain.linkToQuery', () => {
100100
url: '/k8s/ns/default/core~v1~Pod/bad-deployment-000000000-00000',
101101
query: 'k8s:Pod.v1:{"namespace":"default","name":"bad-deployment-000000000-00000"}',
102102
},
103-
{
104-
url: '/k8s/ns/default/core~v1~Pod/bad-deployment-000000000-00000/events',
105-
query: 'k8s:Pod.v1:{"namespace":"default","name":"bad-deployment-000000000-00000"}',
106-
},
107103
{
108104
url: `/k8s/ns/default/core~v1~Pod/foo`,
109105
query: `k8s:Pod.v1:{"namespace":"default","name":"foo"}`,
@@ -119,9 +115,19 @@ describe('K8sDomain.linkToQuery', () => {
119115
{ url: `/k8s/cluster/nodes/oscar7`, query: `k8s:Node.v1:{"name":"oscar7"}` },
120116
{ url: `/api-resource/cluster/core~v1~Node`, query: `k8s:Node.v1:{}` },
121117
{ url: '/k8s/ns/netobserv/core~v1~Pod', query: 'k8s:Pod.v1:{"namespace":"netobserv"}' },
122-
])('converts $url', ({ url, query }) =>
123-
expect(k8s.linkToQuery(new URIRef(url))).toEqual(Query.parse(query)),
124-
);
118+
{
119+
url: '/k8s/ns/foo/core~v1~Pod/bar/events',
120+
query:
121+
'k8s:Event.v1:{"fields":{"involvedObject.namespace":"foo","involvedObject.name":"bar","involvedObject.apiVersion":"v1","involvedObject.kind":"Pod"}}',
122+
},
123+
{
124+
url: '/k8s/ns/openshift-lightspeed/operators.coreos.com~v1alpha1~ClusterServiceVersion/lightspeed-operator.v1.0.5/events',
125+
query:
126+
'k8s:Event.v1:{"fields":{"involvedObject.namespace":"openshift-lightspeed","involvedObject.name":"lightspeed-operator.v1.0.5","involvedObject.apiVersion":"operators.coreos.com/v1alpha1","involvedObject.kind":"ClusterServiceVersion"}}',
127+
},
128+
])('converts $url', ({ url, query }) => {
129+
expect(k8s.linkToQuery(new URIRef(url))).toEqual(Query.parse(query));
130+
});
125131
});
126132

127133
describe('K8sDomain.queryToLink', () => {

web/src/korrel8r/k8s.ts

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ type Selector = {
1919
};
2020

2121
const pathRE = new RegExp(
22-
'(?<prefix>k8s|search|api-resource)' +
23-
'/((ns/(?<namespace>[^/]+))|cluster|all-namespaces)' +
24-
'(/(?<resource>[^/]+)(/(?<name>([^/]+))(?<events>/events)?)?)?',
22+
'(?<prefix>k8s|search|api-resource)' + // prefix
23+
'/((ns/(?<namespace>[^/]+))|cluster|all-namespaces)' + // /namespace
24+
'(/(?<resource>[^/]+)(/(?<name>([^/]+))(?<events>/events)?)?)?', // [/resource[/name[/events]]]
2525
);
26+
2627
const versionRE = /(?<version>v[0-9]+((alpha|beta)[0-9]*)?)/;
2728
const classRE = new RegExp(`^(?<kind>[^./]+)(\\.${versionRE.source})?(.(?<group>[^/]*))?$`);
2829

@@ -55,13 +56,30 @@ export class K8sDomain extends Domain {
5556
const resource = g.resource || link.searchParams.get('kind');
5657
const model = findResource(resource);
5758
if (!model?.kind) throw this.badLink(link, `unknown resource: ${resource}`);
59+
// api-resource is a resource type not a named instance, ignore the name part of the URL.
5860
const name = g.prefix === 'api-resource' ? undefined : g.name;
59-
const data = {
60-
namespace: g.namespace,
61-
name,
62-
labels: K8sDomain.parseSelector(link.searchParams.get('labels')) || undefined,
63-
};
64-
return this.modelClass(model).query(JSON.stringify(data));
61+
if (g.events) {
62+
// Special case for /events, query for events with this resource as involved object
63+
const event = eventModel();
64+
const about = eventAboutField(event);
65+
const apiVersion = `${model.apiGroup ? `${model.apiGroup}/` : ''}${model.apiVersion || 'v1'}`;
66+
const data = {
67+
fields: {
68+
[`${about}.namespace`]: g.namespace,
69+
[`${about}.name`]: name,
70+
[`${about}.apiVersion`]: apiVersion,
71+
[`${about}.kind`]: model.kind,
72+
},
73+
};
74+
return this.modelClass(event).query(JSON.stringify(data));
75+
} else {
76+
const data = {
77+
namespace: g.namespace,
78+
name,
79+
labels: K8sDomain.parseSelector(link.searchParams.get('labels')) || undefined,
80+
};
81+
return this.modelClass(model).query(JSON.stringify(data));
82+
}
6583
}
6684

6785
// NOTE: k8s queries don't support query constraints, so neither do console k8s URIs.
@@ -78,7 +96,7 @@ export class K8sDomain extends Domain {
7896
let name = selector.name;
7997
let events = '';
8098
if (isEvent(model)) {
81-
// Special case for events, use involved object with '/events' modifier.
99+
// Special case for events, generate URL of involved object with '/events' modifier.
82100
const eventClass = this.modelClass(model);
83101
const about = eventAboutField(model);
84102
const [group, version] = parseAPIVersion(selector.fields[`${about}.apiVersion`]);
@@ -134,6 +152,12 @@ function isEvent(m: Model): boolean {
134152
);
135153
}
136154

155+
// Returns an event resource model that is supported by the cluster.
156+
// Prefer the older version as there are still many older clusters out there.
157+
function eventModel(): Model {
158+
return findGVK('', EVENT.version, EVENT.kind) || findGVK(EVENT.group, EVENT.version, EVENT.kind);
159+
}
160+
137161
function eventAboutField(m: Model): string {
138162
return m?.apiGroup === EVENT.group ? 'regarding' : 'involvedObject';
139163
}

0 commit comments

Comments
 (0)