pr feedback
parent
896e8fb7e8
commit
54adcbb959
|
|
@ -4576,13 +4576,38 @@ class KubernetesStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static async watchUntilPVCNotPending(kubeClient, name, namespace) {
|
static async watchUntilPVCNotPending(kubeClient, name, namespace) {
|
||||||
|
let checkCount = 0;
|
||||||
try {
|
try {
|
||||||
cloud_runner_logger_1.default.log(`watch Until PVC Not Pending ${name} ${namespace}`);
|
cloud_runner_logger_1.default.log(`watch Until PVC Not Pending ${name} ${namespace}`);
|
||||||
const initialPhase = await this.getPVCPhase(kubeClient, name, namespace);
|
const initialPhase = await this.getPVCPhase(kubeClient, name, namespace);
|
||||||
cloud_runner_logger_1.default.log(`Initial PVC phase: ${initialPhase}`);
|
cloud_runner_logger_1.default.log(`Initial PVC phase: ${initialPhase}`);
|
||||||
// Wait until PVC is NOT Pending (i.e., Bound or Available)
|
// Wait until PVC is NOT Pending (i.e., Bound or Available)
|
||||||
await (0, async_wait_until_1.waitUntil)(async () => {
|
await (0, async_wait_until_1.waitUntil)(async () => {
|
||||||
|
checkCount++;
|
||||||
const phase = await this.getPVCPhase(kubeClient, name, namespace);
|
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';
|
return phase !== 'Pending';
|
||||||
}, {
|
}, {
|
||||||
timeout: 750000,
|
timeout: 750000,
|
||||||
|
|
@ -4599,12 +4624,65 @@ class KubernetesStorage {
|
||||||
core.error(error.toString());
|
core.error(error.toString());
|
||||||
try {
|
try {
|
||||||
const pvcBody = (await kubeClient.readNamespacedPersistentVolumeClaim(name, namespace)).body;
|
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({
|
core.error(`PVC Body: ${JSON.stringify({
|
||||||
phase: pvcBody.status?.phase,
|
phase: pvcBody.status?.phase,
|
||||||
conditions: pvcBody.status?.conditions,
|
conditions: pvcBody.status?.conditions,
|
||||||
accessModes: pvcBody.spec?.accessModes,
|
accessModes: pvcBody.spec?.accessModes,
|
||||||
storageClassName: pvcBody.spec?.storageClassName,
|
storageClassName: pvcBody.spec?.storageClassName,
|
||||||
|
storageRequest: pvcBody.spec?.resources?.requests?.storage,
|
||||||
}, undefined, 4)}`);
|
}, 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 {
|
catch {
|
||||||
// Ignore PVC read errors
|
// Ignore PVC read errors
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -47,6 +47,7 @@ class KubernetesStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async watchUntilPVCNotPending(kubeClient: k8s.CoreV1Api, name: string, namespace: string) {
|
public static async watchUntilPVCNotPending(kubeClient: k8s.CoreV1Api, name: string, namespace: string) {
|
||||||
|
let checkCount = 0;
|
||||||
try {
|
try {
|
||||||
CloudRunnerLogger.log(`watch Until PVC Not Pending ${name} ${namespace}`);
|
CloudRunnerLogger.log(`watch Until PVC Not Pending ${name} ${namespace}`);
|
||||||
const initialPhase = await this.getPVCPhase(kubeClient, 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)
|
// Wait until PVC is NOT Pending (i.e., Bound or Available)
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
async () => {
|
async () => {
|
||||||
|
checkCount++;
|
||||||
const phase = await this.getPVCPhase(kubeClient, name, namespace);
|
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';
|
return phase !== 'Pending';
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -75,6 +103,49 @@ class KubernetesStorage {
|
||||||
core.error(error.toString());
|
core.error(error.toString());
|
||||||
try {
|
try {
|
||||||
const pvcBody = (await kubeClient.readNamespacedPersistentVolumeClaim(name, namespace)).body;
|
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(
|
core.error(
|
||||||
`PVC Body: ${JSON.stringify(
|
`PVC Body: ${JSON.stringify(
|
||||||
{
|
{
|
||||||
|
|
@ -82,11 +153,22 @@ class KubernetesStorage {
|
||||||
conditions: pvcBody.status?.conditions,
|
conditions: pvcBody.status?.conditions,
|
||||||
accessModes: pvcBody.spec?.accessModes,
|
accessModes: pvcBody.spec?.accessModes,
|
||||||
storageClassName: pvcBody.spec?.storageClassName,
|
storageClassName: pvcBody.spec?.storageClassName,
|
||||||
|
storageRequest: pvcBody.spec?.resources?.requests?.storage,
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
4,
|
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 {
|
} catch {
|
||||||
// Ignore PVC read errors
|
// Ignore PVC read errors
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue