Skip to content

Commit e91507a

Browse files
authored
Merge pull request #2688 from kubernetes-client/yaml3
Fix Knative Service YAML parsing by checking API groups
2 parents a594a8d + 1df31a4 commit e91507a

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

src/util.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,58 @@ export function normalizeResponseHeaders(response: Response): { [key: string]: s
165165
return normalizedHeaders;
166166
}
167167

168+
/**
169+
* Built-in Kubernetes API groups that have generated TypeScript models.
170+
* Custom resources and third-party API groups (like Knative) are not included.
171+
*/
172+
const BUILT_IN_API_GROUPS = new Set([
173+
'core', // maps to "" (empty string) for core resources like Pod, Service, etc.
174+
'admissionregistration.k8s.io',
175+
'apiextensions.k8s.io',
176+
'apiregistration.k8s.io',
177+
'apps',
178+
'authentication.k8s.io',
179+
'authorization.k8s.io',
180+
'autoscaling',
181+
'batch',
182+
'certificates.k8s.io',
183+
'coordination.k8s.io',
184+
'discovery.k8s.io',
185+
'events.k8s.io',
186+
'flowcontrol.apiserver.k8s.io',
187+
'internal.apiserver.k8s.io',
188+
'networking.k8s.io',
189+
'node.k8s.io',
190+
'policy',
191+
'rbac.authorization.k8s.io',
192+
'resource.k8s.io',
193+
'scheduling.k8s.io',
194+
'storage.k8s.io',
195+
'storagemigration.k8s.io',
196+
]);
197+
198+
/**
199+
* Check if the given API group is a built-in Kubernetes API group.
200+
* @param group - The API group to check (e.g., "apps", "serving.knative.dev", "core")
201+
* @returns true if the group is a built-in Kubernetes API group, false otherwise
202+
*/
203+
function isBuiltInApiGroup(group: string): boolean {
204+
return BUILT_IN_API_GROUPS.has(group);
205+
}
206+
168207
export function getSerializationType(apiVersion?: string, kind?: string): string {
169208
if (apiVersion === undefined || kind === undefined) {
170209
return 'KubernetesObject';
171210
}
172211
// Types are defined in src/gen/api/models with the format "<Version><Kind>".
173212
// Version and Kind are in PascalCase.
174213
const gv = groupVersion(apiVersion);
214+
215+
// Only return a type name if this is a built-in Kubernetes API group
216+
if (!isBuiltInApiGroup(gv.group)) {
217+
return 'KubernetesObject';
218+
}
219+
175220
const version = gv.version.charAt(0).toUpperCase() + gv.version.slice(1);
176221
return `${version}${kind}`;
177222
}

src/util_test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,18 @@ describe('Utils', () => {
147147
it('should get the serialization type correctly', () => {
148148
strictEqual(getSerializationType('v1', 'Pod'), 'V1Pod');
149149
strictEqual(getSerializationType('apps/v1', 'Deployment'), 'V1Deployment');
150+
// Built-in Kubernetes resources should return a type
151+
strictEqual(getSerializationType('v1', 'Pod'), 'V1Pod');
152+
strictEqual(getSerializationType('apps/v1', 'Deployment'), 'V1Deployment');
153+
strictEqual(getSerializationType('v1', 'Service'), 'V1Service');
154+
strictEqual(getSerializationType('batch/v1', 'Job'), 'V1Job');
155+
156+
// Non-built-in resources should return 'KubernetesObject'
157+
strictEqual(getSerializationType('serving.knative.dev/v1', 'Service'), 'KubernetesObject');
158+
strictEqual(getSerializationType('example.com/v1', 'MyCustomResource'), 'KubernetesObject');
159+
strictEqual(getSerializationType('custom.io/v1alpha1', 'CustomThing'), 'KubernetesObject');
160+
161+
// Undefined inputs should return 'KubernetesObject'
150162
strictEqual(getSerializationType(undefined, undefined), 'KubernetesObject');
151163
});
152164
});

src/yaml_test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { describe, it } from 'node:test';
22
import { deepEqual, deepStrictEqual, strictEqual } from 'node:assert';
33
import { V1CustomResourceDefinition, V1Namespace } from './api.js';
44
import { dumpYaml, loadAllYaml, loadYaml } from './yaml.js';
5+
import { KubernetesObject } from './types.js';
56

67
describe('yaml', () => {
78
it('should load safely', () => {
@@ -154,4 +155,54 @@ spec:
154155
// not using strict equality as types are not matching
155156
deepEqual(actual, expected);
156157
});
158+
159+
it('should load Knative Service correctly preserving spec', () => {
160+
const yaml = `apiVersion: serving.knative.dev/v1
161+
kind: Service
162+
metadata:
163+
name: hello-world
164+
spec:
165+
template:
166+
spec:
167+
containers:
168+
- image: ghcr.io/knative/helloworld-go:latest
169+
ports:
170+
- containerPort: 8080
171+
env:
172+
- name: TARGET
173+
value: "World"`;
174+
const knativeService = loadYaml(yaml) as KubernetesObject;
175+
176+
strictEqual(knativeService.apiVersion, 'serving.knative.dev/v1');
177+
strictEqual(knativeService.kind, 'Service');
178+
strictEqual((knativeService as any).metadata.name, 'hello-world');
179+
// Verify that the spec is preserved
180+
strictEqual(
181+
(knativeService as any).spec.template.spec.containers[0].image,
182+
'ghcr.io/knative/helloworld-go:latest',
183+
);
184+
strictEqual((knativeService as any).spec.template.spec.containers[0].ports[0].containerPort, 8080);
185+
strictEqual((knativeService as any).spec.template.spec.containers[0].env[0].name, 'TARGET');
186+
strictEqual((knativeService as any).spec.template.spec.containers[0].env[0].value, 'World');
187+
});
188+
189+
it('should load custom resources correctly', () => {
190+
const yaml = `apiVersion: example.com/v1
191+
kind: MyCustomResource
192+
metadata:
193+
name: my-resource
194+
spec:
195+
customField: customValue
196+
nestedObject:
197+
key1: value1
198+
key2: value2`;
199+
const customResource = loadYaml(yaml) as KubernetesObject;
200+
201+
strictEqual((customResource as any).apiVersion, 'example.com/v1');
202+
strictEqual((customResource as any).kind, 'MyCustomResource');
203+
strictEqual((customResource as any).metadata.name, 'my-resource');
204+
strictEqual((customResource as any).spec.customField, 'customValue');
205+
strictEqual((customResource as any).spec.nestedObject.key1, 'value1');
206+
strictEqual((customResource as any).spec.nestedObject.key2, 'value2');
207+
});
157208
});

0 commit comments

Comments
 (0)