pr feedback

cloud-runner-develop
Frostebite 2026-01-18 15:06:34 +00:00
parent 896e8fb7e8
commit 54adcbb959
3 changed files with 161 additions and 1 deletions

78
dist/index.js vendored
View File

@ -4576,13 +4576,38 @@ class KubernetesStorage {
}
}
static async watchUntilPVCNotPending(kubeClient, name, namespace) {
let checkCount = 0;
try {
cloud_runner_logger_1.default.log(`watch Until PVC Not Pending ${name} ${namespace}`);
const initialPhase = await this.getPVCPhase(kubeClient, name, namespace);
cloud_runner_logger_1.default.log(`Initial PVC phase: ${initialPhase}`);
// Wait until PVC is NOT Pending (i.e., Bound or Available)
await (0, async_wait_until_1.waitUntil)(async () => {
checkCount++;
const phase = await this.getPVCPhase(kubeClient, name, namespace);
// Log progress every 4 checks (every ~60 seconds)
if (checkCount % 4 === 0) {
cloud_runner_logger_1.default.log(`PVC ${name} still ${phase} (check ${checkCount})`);
// Fetch and log PVC events for diagnostics
try {
const events = await kubeClient.listNamespacedEvent(namespace);
const pvcEvents = events.body.items
.filter((x) => x.involvedObject?.kind === 'PersistentVolumeClaim' && x.involvedObject?.name === name)
.map((x) => ({
message: x.message || '',
reason: x.reason || '',
type: x.type || '',
count: x.count || 0,
}))
.slice(-5); // Get last 5 events
if (pvcEvents.length > 0) {
cloud_runner_logger_1.default.log(`PVC Events: ${JSON.stringify(pvcEvents, undefined, 2)}`);
}
}
catch (eventError) {
// Ignore event fetch errors
}
}
return phase !== 'Pending';
}, {
timeout: 750000,
@ -4599,12 +4624,65 @@ class KubernetesStorage {
core.error(error.toString());
try {
const pvcBody = (await kubeClient.readNamespacedPersistentVolumeClaim(name, namespace)).body;
// Fetch PVC events for detailed diagnostics
let pvcEvents = [];
try {
const events = await kubeClient.listNamespacedEvent(namespace);
pvcEvents = events.body.items
.filter((x) => x.involvedObject?.kind === 'PersistentVolumeClaim' && x.involvedObject?.name === name)
.map((x) => ({
message: x.message || '',
reason: x.reason || '',
type: x.type || '',
count: x.count || 0,
}));
}
catch (eventError) {
// Ignore event fetch errors
}
// Check if storage class exists
let storageClassInfo = '';
try {
const storageClassName = pvcBody.spec?.storageClassName;
if (storageClassName) {
// Create StorageV1Api from default config
const kubeConfig = new k8s.KubeConfig();
kubeConfig.loadFromDefault();
const storageV1Api = kubeConfig.makeApiClient(k8s.StorageV1Api);
try {
const sc = await storageV1Api.readStorageClass(storageClassName);
storageClassInfo = `StorageClass "${storageClassName}" exists. Provisioner: ${sc.body.provisioner || 'unknown'}`;
}
catch (scError) {
if (scError.statusCode === 404) {
storageClassInfo = `StorageClass "${storageClassName}" does NOT exist! This is likely why the PVC is stuck in Pending.`;
}
else {
storageClassInfo = `Failed to check StorageClass "${storageClassName}": ${scError.message || scError}`;
}
}
}
}
catch (scCheckError) {
// Ignore storage class check errors - not critical for diagnostics
storageClassInfo = `Could not check storage class: ${scCheckError}`;
}
core.error(`PVC Body: ${JSON.stringify({
phase: pvcBody.status?.phase,
conditions: pvcBody.status?.conditions,
accessModes: pvcBody.spec?.accessModes,
storageClassName: pvcBody.spec?.storageClassName,
storageRequest: pvcBody.spec?.resources?.requests?.storage,
}, undefined, 4)}`);
if (storageClassInfo) {
core.error(storageClassInfo);
}
if (pvcEvents.length > 0) {
core.error(`PVC Events: ${JSON.stringify(pvcEvents, undefined, 2)}`);
}
else {
core.error('No PVC events found - this may indicate the storage provisioner is not responding');
}
}
catch {
// Ignore PVC read errors

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -47,6 +47,7 @@ class KubernetesStorage {
}
public static async watchUntilPVCNotPending(kubeClient: k8s.CoreV1Api, name: string, namespace: string) {
let checkCount = 0;
try {
CloudRunnerLogger.log(`watch Until PVC Not Pending ${name} ${namespace}`);
const initialPhase = await this.getPVCPhase(kubeClient, name, namespace);
@ -55,7 +56,34 @@ class KubernetesStorage {
// Wait until PVC is NOT Pending (i.e., Bound or Available)
await waitUntil(
async () => {
checkCount++;
const phase = await this.getPVCPhase(kubeClient, name, namespace);
// Log progress every 4 checks (every ~60 seconds)
if (checkCount % 4 === 0) {
CloudRunnerLogger.log(`PVC ${name} still ${phase} (check ${checkCount})`);
// Fetch and log PVC events for diagnostics
try {
const events = await kubeClient.listNamespacedEvent(namespace);
const pvcEvents = events.body.items
.filter((x) => x.involvedObject?.kind === 'PersistentVolumeClaim' && x.involvedObject?.name === name)
.map((x) => ({
message: x.message || '',
reason: x.reason || '',
type: x.type || '',
count: x.count || 0,
}))
.slice(-5); // Get last 5 events
if (pvcEvents.length > 0) {
CloudRunnerLogger.log(`PVC Events: ${JSON.stringify(pvcEvents, undefined, 2)}`);
}
} catch (eventError) {
// Ignore event fetch errors
}
}
return phase !== 'Pending';
},
{
@ -75,6 +103,49 @@ class KubernetesStorage {
core.error(error.toString());
try {
const pvcBody = (await kubeClient.readNamespacedPersistentVolumeClaim(name, namespace)).body;
// Fetch PVC events for detailed diagnostics
let pvcEvents: any[] = [];
try {
const events = await kubeClient.listNamespacedEvent(namespace);
pvcEvents = events.body.items
.filter((x) => x.involvedObject?.kind === 'PersistentVolumeClaim' && x.involvedObject?.name === name)
.map((x) => ({
message: x.message || '',
reason: x.reason || '',
type: x.type || '',
count: x.count || 0,
}));
} catch (eventError) {
// Ignore event fetch errors
}
// Check if storage class exists
let storageClassInfo = '';
try {
const storageClassName = pvcBody.spec?.storageClassName;
if (storageClassName) {
// Create StorageV1Api from default config
const kubeConfig = new k8s.KubeConfig();
kubeConfig.loadFromDefault();
const storageV1Api = kubeConfig.makeApiClient(k8s.StorageV1Api);
try {
const sc = await storageV1Api.readStorageClass(storageClassName);
storageClassInfo = `StorageClass "${storageClassName}" exists. Provisioner: ${sc.body.provisioner || 'unknown'}`;
} catch (scError: any) {
if (scError.statusCode === 404) {
storageClassInfo = `StorageClass "${storageClassName}" does NOT exist! This is likely why the PVC is stuck in Pending.`;
} else {
storageClassInfo = `Failed to check StorageClass "${storageClassName}": ${scError.message || scError}`;
}
}
}
} catch (scCheckError) {
// Ignore storage class check errors - not critical for diagnostics
storageClassInfo = `Could not check storage class: ${scCheckError}`;
}
core.error(
`PVC Body: ${JSON.stringify(
{
@ -82,11 +153,22 @@ class KubernetesStorage {
conditions: pvcBody.status?.conditions,
accessModes: pvcBody.spec?.accessModes,
storageClassName: pvcBody.spec?.storageClassName,
storageRequest: pvcBody.spec?.resources?.requests?.storage,
},
undefined,
4,
)}`,
);
if (storageClassInfo) {
core.error(storageClassInfo);
}
if (pvcEvents.length > 0) {
core.error(`PVC Events: ${JSON.stringify(pvcEvents, undefined, 2)}`);
} else {
core.error('No PVC events found - this may indicate the storage provisioner is not responding');
}
} catch {
// Ignore PVC read errors
}