mirror of
https://github.com/tale/headplane.git
synced 2026-08-31 17:28:14 +00:00
feat: upgrade to kubernetes client 1.x
This commit is contained in:
@@ -3,13 +3,18 @@ import { platform } from 'node:os';
|
|||||||
import { join, resolve } from 'node:path';
|
import { join, resolve } from 'node:path';
|
||||||
import { kill } from 'node:process';
|
import { kill } from 'node:process';
|
||||||
import { setTimeout } from 'node:timers/promises';
|
import { setTimeout } from 'node:timers/promises';
|
||||||
import { Config, CoreV1Api, KubeConfig } from '@kubernetes/client-node';
|
import { CoreV1Api, KubeConfig } from '@kubernetes/client-node';
|
||||||
import { ApiClient } from '~/server/headscale/api-client';
|
import { ApiClient } from '~/server/headscale/api-client';
|
||||||
import log from '~/utils/log';
|
import log from '~/utils/log';
|
||||||
import { HeadplaneConfig } from '../schema';
|
import { HeadplaneConfig } from '../schema';
|
||||||
import { Integration } from './abstract';
|
import { Integration } from './abstract';
|
||||||
|
|
||||||
// TODO: Upgrade to the new CoreV1Api from @kubernetes/client-node
|
// https://github.com/kubernetes-client/javascript/blob/055b83c6504dfd1b2a2d081efd974163c6cbb808/src/config.ts#L40
|
||||||
|
const svcRoot = '/var/run/secrets/kubernetes.io/serviceaccount';
|
||||||
|
const svcCaPath = `${svcRoot}/ca.crt`;
|
||||||
|
const svcTokenPath = `${svcRoot}/token`;
|
||||||
|
const svcNamespacePath = `${svcRoot}/namespace`;
|
||||||
|
|
||||||
type T = NonNullable<HeadplaneConfig['integration']>['kubernetes'];
|
type T = NonNullable<HeadplaneConfig['integration']>['kubernetes'];
|
||||||
export default class KubernetesIntegration extends Integration<T> {
|
export default class KubernetesIntegration extends Integration<T> {
|
||||||
private pid: number | undefined;
|
private pid: number | undefined;
|
||||||
@@ -25,7 +30,6 @@ export default class KubernetesIntegration extends Integration<T> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const svcRoot = Config.SERVICEACCOUNT_ROOT;
|
|
||||||
try {
|
try {
|
||||||
log.debug('config', 'Checking Kubernetes service account at %s', svcRoot);
|
log.debug('config', 'Checking Kubernetes service account at %s', svcRoot);
|
||||||
const files = await readdir(svcRoot);
|
const files = await readdir(svcRoot);
|
||||||
@@ -35,11 +39,7 @@ export default class KubernetesIntegration extends Integration<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mappedFiles = new Set(files.map((file) => join(svcRoot, file)));
|
const mappedFiles = new Set(files.map((file) => join(svcRoot, file)));
|
||||||
const expectedFiles = [
|
const expectedFiles = [svcCaPath, svcTokenPath, svcNamespacePath];
|
||||||
Config.SERVICEACCOUNT_CA_PATH,
|
|
||||||
Config.SERVICEACCOUNT_TOKEN_PATH,
|
|
||||||
Config.SERVICEACCOUNT_NAMESPACE_PATH,
|
|
||||||
];
|
|
||||||
|
|
||||||
log.debug('config', 'Looking for %s', expectedFiles.join(', '));
|
log.debug('config', 'Looking for %s', expectedFiles.join(', '));
|
||||||
if (!expectedFiles.every((file) => mappedFiles.has(file))) {
|
if (!expectedFiles.every((file) => mappedFiles.has(file))) {
|
||||||
@@ -52,10 +52,7 @@ export default class KubernetesIntegration extends Integration<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.debug('config', 'Reading Kubernetes service account at %s', svcRoot);
|
log.debug('config', 'Reading Kubernetes service account at %s', svcRoot);
|
||||||
const namespace = await readFile(
|
const namespace = await readFile(svcNamespacePath, 'utf8');
|
||||||
Config.SERVICEACCOUNT_NAMESPACE_PATH,
|
|
||||||
'utf8',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Some very ugly nesting but it's necessary
|
// Some very ugly nesting but it's necessary
|
||||||
if (this.context.validate_manifest === false) {
|
if (this.context.validate_manifest === false) {
|
||||||
@@ -99,36 +96,32 @@ export default class KubernetesIntegration extends Integration<T> {
|
|||||||
|
|
||||||
const kCoreV1Api = kc.makeApiClient(CoreV1Api);
|
const kCoreV1Api = kc.makeApiClient(CoreV1Api);
|
||||||
|
|
||||||
log.info(
|
log.info('config', 'Checking pod %s in namespace %s', pod, namespace);
|
||||||
'config',
|
|
||||||
'Checking pod %s in namespace %s (%s)',
|
|
||||||
pod,
|
|
||||||
namespace,
|
|
||||||
kCoreV1Api.basePath,
|
|
||||||
);
|
|
||||||
|
|
||||||
log.debug('config', 'Reading pod info for %s', pod);
|
log.debug('config', 'Reading pod info for %s', pod);
|
||||||
const { response, body } = await kCoreV1Api.readNamespacedPod(
|
const body = await kCoreV1Api.readNamespacedPod({
|
||||||
pod,
|
name: pod,
|
||||||
namespace,
|
namespace,
|
||||||
);
|
});
|
||||||
|
|
||||||
if (response.statusCode !== 200) {
|
if (!body.spec) {
|
||||||
log.error(
|
log.error(
|
||||||
'config',
|
'config',
|
||||||
'Failed to read pod info: http %d',
|
'Missing spec in pod info for %s/%s',
|
||||||
response.statusCode,
|
pod,
|
||||||
|
namespace,
|
||||||
);
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug('config', 'Got pod info: %o', body.spec);
|
log.debug('config', 'Got pod info: %o', body.spec);
|
||||||
const shared = body.spec?.shareProcessNamespace;
|
const shared = body.spec.shareProcessNamespace;
|
||||||
if (shared === undefined) {
|
if (shared === undefined) {
|
||||||
log.error(
|
log.error(
|
||||||
'config',
|
'config',
|
||||||
'Pod does not have spec.shareProcessNamespace set',
|
'Pod does not have spec.shareProcessNamespace set',
|
||||||
);
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +130,7 @@ export default class KubernetesIntegration extends Integration<T> {
|
|||||||
'config',
|
'config',
|
||||||
'Pod has set but disabled spec.shareProcessNamespace',
|
'Pod has set but disabled spec.shareProcessNamespace',
|
||||||
);
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@
|
|||||||
"@dnd-kit/sortable": "^8.0.0",
|
"@dnd-kit/sortable": "^8.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
"@fontsource-variable/inter": "^5.2.5",
|
"@fontsource-variable/inter": "^5.2.5",
|
||||||
"@kubernetes/client-node": "^0.22.3",
|
"@kubernetes/client-node": "^1.3.0",
|
||||||
"@primer/octicons-react": "^19.15.2",
|
"@primer/octicons-react": "^19.15.2",
|
||||||
"@react-aria/toast": "3.0.3",
|
"@react-aria/toast": "3.0.3",
|
||||||
"@react-router/node": "^7.6.1",
|
"@react-router/node": "^7.6.1",
|
||||||
|
|||||||
Generated
+397
-319
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user