Skip to content

Commit 46a6327

Browse files
committed
fix: preserve Knative-managed annotations on ksvc replace
The Knative admission webhook rejects replace (PUT) when immutable annotations like serving.knative.dev/creator are missing. Now the replace path fetches the existing service first and merges its annotations and labels into the new spec.
1 parent a1f8d90 commit 46a6327

3 files changed

Lines changed: 18 additions & 8 deletions

File tree

packages/provisioning-handlers/src/handlers/function-sync-resources.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,18 @@ export const handleFunctionSyncResources: ProvisioningHandler = async (
6767
const serviceSpec = buildKnativeServiceSpec(fnRow, namespaceName);
6868

6969
try {
70-
// GET the existing service to retrieve its resourceVersion (required for PUT)
70+
// GET the existing service to retrieve metadata required for PUT
7171
const existing = await client.readServingKnativeDevV1NamespacedService({
7272
query: {},
7373
path: { name: fnName, namespace: namespaceName },
7474
});
75-
const resourceVersion = existing?.metadata?.resourceVersion;
76-
if (resourceVersion && serviceSpec.metadata) {
77-
serviceSpec.metadata.resourceVersion = resourceVersion;
75+
if (serviceSpec.metadata) {
76+
serviceSpec.metadata.resourceVersion = existing?.metadata?.resourceVersion;
77+
// Preserve Knative-managed annotations (e.g. serving.knative.dev/creator)
78+
const existingAnnotations = (existing?.metadata?.annotations ?? {}) as Record<string, string>;
79+
serviceSpec.metadata.annotations = { ...existingAnnotations, ...serviceSpec.metadata.annotations };
80+
const existingLabels = (existing?.metadata?.labels ?? {}) as Record<string, string>;
81+
serviceSpec.metadata.labels = { ...existingLabels, ...serviceSpec.metadata.labels };
7882
}
7983

8084
const svc = await client.replaceServingKnativeDevV1NamespacedService({

packages/provisioning-handlers/src/knative.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export function buildKnativeServiceSpec(
3131
name: string;
3232
namespace: string;
3333
resourceVersion?: string;
34+
annotations?: Record<string, string>;
35+
labels?: Record<string, string>;
3436
},
3537
spec: {
3638
template: {

packages/provisioning-handlers/src/seed.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,14 +191,18 @@ export async function provision(opts: ProvisionSeedOptions): Promise<ProvisionSe
191191
result.functions.push({ name: fnName, namespace: namespaceName, serviceUrl, status: 'created' });
192192
} catch (err: unknown) {
193193
if (isConflict(err)) {
194-
// GET the existing service to retrieve its resourceVersion (required for PUT)
194+
// GET the existing service to retrieve metadata required for PUT
195195
const existing = await client.readServingKnativeDevV1NamespacedService({
196196
query: {},
197197
path: { name: fnName, namespace: namespaceName },
198198
});
199-
const resourceVersion = existing?.metadata?.resourceVersion;
200-
if (resourceVersion && serviceSpec.metadata) {
201-
serviceSpec.metadata.resourceVersion = resourceVersion;
199+
if (serviceSpec.metadata) {
200+
serviceSpec.metadata.resourceVersion = existing?.metadata?.resourceVersion;
201+
// Preserve Knative-managed annotations (e.g. serving.knative.dev/creator)
202+
const existingAnnotations = (existing?.metadata?.annotations ?? {}) as Record<string, string>;
203+
serviceSpec.metadata.annotations = { ...existingAnnotations, ...serviceSpec.metadata.annotations };
204+
const existingLabels = (existing?.metadata?.labels ?? {}) as Record<string, string>;
205+
serviceSpec.metadata.labels = { ...existingLabels, ...serviceSpec.metadata.labels };
202206
}
203207

204208
const svc = await client.replaceServingKnativeDevV1NamespacedService({

0 commit comments

Comments
 (0)