fix(ci): ignore terminating CloudNativePG rollout remnants

This commit is contained in:
whyour
2026-09-04 04:21:17 +08:00
parent 03afd7e899
commit 2005cb6ba9
2 changed files with 59 additions and 4 deletions
+13 -2
View File
@@ -485,14 +485,24 @@ function verifyImageIds(pods, expectedDigests, description) {
return [...new Set(imageIds)];
}
function operatorPods() {
return kubectlJson(['-n', 'cnpg-system', 'get', 'pods']).items.filter((pod) =>
function activeOperatorPods(pods) {
// A successful Deployment rollout can leave the old Pod terminating with
// an empty imageID. It is not evidence for the new serving generation.
return pods.filter(
(pod) =>
!pod.metadata?.deletionTimestamp &&
(pod.spec?.containers || []).some((container) =>
container.image.includes('cloudnative-pg'),
),
);
}
function operatorPods() {
return activeOperatorPods(
kubectlJson(['-n', 'cnpg-system', 'get', 'pods']).items,
);
}
function nodeReady(name) {
const node = kubectlJson(['get', 'node', name]);
return node.status?.conditions?.some(
@@ -1034,6 +1044,7 @@ if (require.main === module) {
}
module.exports = {
activeOperatorPods,
imageDigest,
imageTag,
localApplicationManifest,
@@ -5,6 +5,7 @@ const path = require('node:path');
const { test } = require('node:test');
const {
activeOperatorPods,
imageDigest,
imageTag,
localApplicationManifest,
@@ -20,6 +21,49 @@ const INDEX = `sha256:${'a'.repeat(64)}`;
const PLATFORM = `sha256:${'b'.repeat(64)}`;
const VERSION = readReleaseIdentity(path.resolve(__dirname, '../..')).version;
test('operator image evidence excludes terminating rollout remnants but never missing or unreviewed live pods', () => {
const operator = (imageID, deleting = false) => ({
metadata: deleting ? { deletionTimestamp: '2026-09-03T20:00:17Z' } : {},
spec: {
containers: [
{ image: `ghcr.io/cloudnative-pg/cloudnative-pg:1.30.0@${INDEX}` },
],
},
status: { containerStatuses: [{ imageID }] },
});
const live = operator(`ghcr.io/cloudnative-pg/cloudnative-pg@${PLATFORM}`);
const old = operator('', true);
assert.throws(() =>
verifyImageIds([live, old], [INDEX, PLATFORM], 'operator'),
);
assert.deepEqual(activeOperatorPods([live, old]), [live]);
assert.deepEqual(
verifyImageIds(
activeOperatorPods([live, old]),
[INDEX, PLATFORM],
'operator',
),
[`ghcr.io/cloudnative-pg/cloudnative-pg@${PLATFORM}`],
);
assert.throws(() =>
verifyImageIds(activeOperatorPods([old]), [INDEX], 'operator'),
);
assert.throws(() =>
verifyImageIds(
activeOperatorPods([live, operator('')]),
[INDEX, PLATFORM],
'operator',
),
);
assert.throws(() =>
verifyImageIds(
activeOperatorPods([live, operator(`sha256:${'c'.repeat(64)}`)]),
[INDEX, PLATFORM],
'operator',
),
);
});
function pods(...imageIds) {
return imageIds.map((imageID) => ({
status: { containerStatuses: [{ imageID }] },