@kubernetesjs/cli 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +54 -55
- package/commands/apply.d.ts +4 -0
- package/commands/apply.js +171 -0
- package/commands/cluster-info.d.ts +4 -0
- package/commands/cluster-info.js +26 -0
- package/commands/config-handler.d.ts +11 -0
- package/commands/config-handler.js +81 -0
- package/commands/config.d.ts +4 -0
- package/commands/config.js +72 -0
- package/commands/delete.d.ts +4 -0
- package/commands/delete.js +256 -0
- package/commands/deploy.d.ts +6 -0
- package/commands/deploy.js +209 -0
- package/commands/describe.d.ts +4 -0
- package/commands/describe.js +216 -0
- package/commands/exec.d.ts +4 -0
- package/commands/exec.js +145 -0
- package/commands/get.d.ts +4 -0
- package/commands/get.js +164 -0
- package/commands/logs.d.ts +4 -0
- package/commands/logs.js +110 -0
- package/commands/port-forward.d.ts +4 -0
- package/commands/port-forward.js +143 -0
- package/commands.d.ts +3 -0
- package/commands.js +93 -0
- package/config.d.ts +22 -0
- package/config.js +113 -0
- package/esm/commands/apply.js +133 -0
- package/esm/commands/cluster-info.js +21 -0
- package/esm/commands/config-handler.js +43 -0
- package/esm/commands/config.js +67 -0
- package/esm/commands/delete.js +218 -0
- package/esm/commands/deploy.js +207 -0
- package/esm/commands/describe.js +211 -0
- package/esm/commands/exec.js +140 -0
- package/esm/commands/get.js +159 -0
- package/esm/commands/logs.js +105 -0
- package/esm/commands/port-forward.js +138 -0
- package/esm/commands.js +86 -0
- package/esm/config.js +74 -0
- package/esm/index.js +19 -0
- package/esm/package.js +26 -0
- package/esm/utils.js +49 -0
- package/index.d.ts +3 -0
- package/index.js +22 -0
- package/package.d.ts +1 -0
- package/package.js +29 -0
- package/package.json +37 -61
- package/utils.d.ts +11 -0
- package/utils.js +58 -0
- package/main/client.js +0 -156
- package/main/index.js +0 -2598
- package/module/client.js +0 -129
- package/module/index.js +0 -2594
- package/src/client.ts +0 -156
- package/src/index.ts +0 -14187
- package/types/client.d.ts +0 -31
- package/types/index.d.ts +0 -11331
package/config.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read and parse a YAML file
|
|
3
|
+
* @param filePath Path to the YAML file
|
|
4
|
+
* @returns Parsed YAML content
|
|
5
|
+
*/
|
|
6
|
+
export declare function readYamlFile(filePath: string): any;
|
|
7
|
+
/**
|
|
8
|
+
* Infer the resource type from a Kubernetes YAML
|
|
9
|
+
* @param resource The parsed Kubernetes resource
|
|
10
|
+
* @returns The resource type (lowercase)
|
|
11
|
+
*/
|
|
12
|
+
export declare function inferResourceType(resource: any): string;
|
|
13
|
+
/**
|
|
14
|
+
* Get the current namespace from the local kubeconfig
|
|
15
|
+
* @returns The current namespace
|
|
16
|
+
*/
|
|
17
|
+
export declare function getCurrentNamespace(): string;
|
|
18
|
+
/**
|
|
19
|
+
* Set the current namespace in the local kubeconfig
|
|
20
|
+
* @param namespace The namespace to set
|
|
21
|
+
*/
|
|
22
|
+
export declare function setCurrentNamespace(namespace: string): void;
|
package/config.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.readYamlFile = readYamlFile;
|
|
37
|
+
exports.inferResourceType = inferResourceType;
|
|
38
|
+
exports.getCurrentNamespace = getCurrentNamespace;
|
|
39
|
+
exports.setCurrentNamespace = setCurrentNamespace;
|
|
40
|
+
const fs_1 = require("fs");
|
|
41
|
+
const os_1 = require("os");
|
|
42
|
+
const path_1 = require("path");
|
|
43
|
+
const yaml = __importStar(require("js-yaml"));
|
|
44
|
+
const KUBECONFIG_PATH = (0, path_1.join)((0, os_1.homedir)(), '.kubeconfig');
|
|
45
|
+
const DEFAULT_NAMESPACE = 'default';
|
|
46
|
+
/**
|
|
47
|
+
* Read and parse a YAML file
|
|
48
|
+
* @param filePath Path to the YAML file
|
|
49
|
+
* @returns Parsed YAML content
|
|
50
|
+
*/
|
|
51
|
+
function readYamlFile(filePath) {
|
|
52
|
+
try {
|
|
53
|
+
const fileContent = (0, fs_1.readFileSync)(filePath, 'utf8');
|
|
54
|
+
return yaml.load(fileContent);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.error(`Error reading YAML file: ${error}`);
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Infer the resource type from a Kubernetes YAML
|
|
63
|
+
* @param resource The parsed Kubernetes resource
|
|
64
|
+
* @returns The resource type (lowercase)
|
|
65
|
+
*/
|
|
66
|
+
function inferResourceType(resource) {
|
|
67
|
+
if (!resource || !resource.kind) {
|
|
68
|
+
throw new Error('Invalid Kubernetes resource: missing kind');
|
|
69
|
+
}
|
|
70
|
+
return resource.kind.toLowerCase();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get the current namespace from the local kubeconfig
|
|
74
|
+
* @returns The current namespace
|
|
75
|
+
*/
|
|
76
|
+
function getCurrentNamespace() {
|
|
77
|
+
try {
|
|
78
|
+
if (!(0, fs_1.existsSync)(KUBECONFIG_PATH)) {
|
|
79
|
+
return DEFAULT_NAMESPACE;
|
|
80
|
+
}
|
|
81
|
+
const configContent = (0, fs_1.readFileSync)(KUBECONFIG_PATH, 'utf8');
|
|
82
|
+
const config = JSON.parse(configContent);
|
|
83
|
+
return config.currentNamespace || DEFAULT_NAMESPACE;
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error(`Error reading kubeconfig: ${error}`);
|
|
87
|
+
return DEFAULT_NAMESPACE;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Set the current namespace in the local kubeconfig
|
|
92
|
+
* @param namespace The namespace to set
|
|
93
|
+
*/
|
|
94
|
+
function setCurrentNamespace(namespace) {
|
|
95
|
+
try {
|
|
96
|
+
let config = { currentNamespace: namespace };
|
|
97
|
+
if ((0, fs_1.existsSync)(KUBECONFIG_PATH)) {
|
|
98
|
+
try {
|
|
99
|
+
const configContent = (0, fs_1.readFileSync)(KUBECONFIG_PATH, 'utf8');
|
|
100
|
+
config = { ...JSON.parse(configContent), currentNamespace: namespace };
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.error(`Error parsing existing kubeconfig: ${error}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
(0, fs_1.writeFileSync)(KUBECONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
|
|
107
|
+
console.log(`Namespace set to "${namespace}"`);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.error(`Error setting namespace: ${error}`);
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { KubernetesClient } from 'kubernetesjs';
|
|
3
|
+
import { readYamlFile } from '../config';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
async function promptYamlFilePath(prompter, argv) {
|
|
6
|
+
const question = {
|
|
7
|
+
type: 'text',
|
|
8
|
+
name: 'filePath',
|
|
9
|
+
message: 'Enter path to YAML file',
|
|
10
|
+
required: true
|
|
11
|
+
};
|
|
12
|
+
const { filePath } = await prompter.prompt(argv, [question]);
|
|
13
|
+
return filePath;
|
|
14
|
+
}
|
|
15
|
+
async function applyResource(client, resource, namespace) {
|
|
16
|
+
const kind = resource.kind.toLowerCase();
|
|
17
|
+
const name = resource.metadata?.name;
|
|
18
|
+
if (!name) {
|
|
19
|
+
throw new Error('Resource must have a name');
|
|
20
|
+
}
|
|
21
|
+
console.log(chalk.blue(`Applying ${kind} "${name}" in namespace ${namespace}...`));
|
|
22
|
+
try {
|
|
23
|
+
switch (kind) {
|
|
24
|
+
case 'deployment':
|
|
25
|
+
await client.createAppsV1NamespacedDeployment({
|
|
26
|
+
path: { namespace },
|
|
27
|
+
query: {
|
|
28
|
+
pretty: 'true',
|
|
29
|
+
fieldManager: 'kubernetesjs-cli'
|
|
30
|
+
},
|
|
31
|
+
body: resource
|
|
32
|
+
});
|
|
33
|
+
console.log(chalk.green(`Deployment "${name}" created/updated successfully`));
|
|
34
|
+
break;
|
|
35
|
+
case 'service':
|
|
36
|
+
await client.createCoreV1NamespacedService({
|
|
37
|
+
path: { namespace },
|
|
38
|
+
query: {
|
|
39
|
+
pretty: 'true',
|
|
40
|
+
fieldManager: 'kubernetesjs-cli'
|
|
41
|
+
},
|
|
42
|
+
body: resource
|
|
43
|
+
});
|
|
44
|
+
console.log(chalk.green(`Service "${name}" created/updated successfully`));
|
|
45
|
+
break;
|
|
46
|
+
case 'pod':
|
|
47
|
+
await client.createCoreV1NamespacedPod({
|
|
48
|
+
path: { namespace },
|
|
49
|
+
query: {
|
|
50
|
+
pretty: 'true',
|
|
51
|
+
fieldManager: 'kubernetesjs-cli'
|
|
52
|
+
},
|
|
53
|
+
body: resource
|
|
54
|
+
});
|
|
55
|
+
console.log(chalk.green(`Pod "${name}" created/updated successfully`));
|
|
56
|
+
break;
|
|
57
|
+
case 'configmap':
|
|
58
|
+
await client.createCoreV1NamespacedConfigMap({
|
|
59
|
+
path: { namespace },
|
|
60
|
+
query: {
|
|
61
|
+
pretty: 'true',
|
|
62
|
+
fieldManager: 'kubernetesjs-cli'
|
|
63
|
+
},
|
|
64
|
+
body: resource
|
|
65
|
+
});
|
|
66
|
+
console.log(chalk.green(`ConfigMap "${name}" created/updated successfully`));
|
|
67
|
+
break;
|
|
68
|
+
case 'secret':
|
|
69
|
+
await client.createCoreV1NamespacedSecret({
|
|
70
|
+
path: { namespace },
|
|
71
|
+
query: {
|
|
72
|
+
pretty: 'true',
|
|
73
|
+
fieldManager: 'kubernetesjs-cli'
|
|
74
|
+
},
|
|
75
|
+
body: resource
|
|
76
|
+
});
|
|
77
|
+
console.log(chalk.green(`Secret "${name}" created/updated successfully`));
|
|
78
|
+
break;
|
|
79
|
+
default:
|
|
80
|
+
console.log(chalk.yellow(`Resource kind "${kind}" not implemented yet`));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.error(chalk.red(`Error applying ${kind} "${name}": ${error}`));
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export default async (argv, prompter, _options) => {
|
|
89
|
+
try {
|
|
90
|
+
const client = new KubernetesClient({
|
|
91
|
+
restEndpoint: argv.clientUrl
|
|
92
|
+
});
|
|
93
|
+
const filePath = argv.f || argv._?.[0] || await promptYamlFilePath(prompter, argv);
|
|
94
|
+
if (!filePath) {
|
|
95
|
+
console.error(chalk.red('No file path provided'));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!fs.existsSync(filePath)) {
|
|
99
|
+
console.error(chalk.red(`File not found: ${filePath}`));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let resources;
|
|
103
|
+
try {
|
|
104
|
+
const content = readYamlFile(filePath);
|
|
105
|
+
if (Array.isArray(content)) {
|
|
106
|
+
resources = content;
|
|
107
|
+
}
|
|
108
|
+
else if (content.kind === 'List' && Array.isArray(content.items)) {
|
|
109
|
+
resources = content.items;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
resources = [content];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
console.error(chalk.red(`Error parsing YAML file: ${error}`));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
for (const resource of resources) {
|
|
120
|
+
try {
|
|
121
|
+
const namespace = resource.metadata?.namespace || argv.n || argv.namespace || 'default';
|
|
122
|
+
await applyResource(client, resource, namespace);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.error(chalk.red(`Failed to apply resource: ${error}`));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
console.log(chalk.green('Apply completed'));
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error(chalk.red(`Error: ${error}`));
|
|
132
|
+
}
|
|
133
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { KubernetesClient } from 'kubernetesjs';
|
|
3
|
+
export default async (_argv, _prompter, _options) => {
|
|
4
|
+
try {
|
|
5
|
+
const client = new KubernetesClient({
|
|
6
|
+
restEndpoint: _argv.clientUrl
|
|
7
|
+
});
|
|
8
|
+
console.log(chalk.blue('Kubernetes cluster info:'));
|
|
9
|
+
const apiVersions = await client.getAPIVersions({
|
|
10
|
+
params: {},
|
|
11
|
+
query: {}
|
|
12
|
+
});
|
|
13
|
+
console.log(chalk.bold('\nAPI Versions:'));
|
|
14
|
+
if (apiVersions.apiVersion) {
|
|
15
|
+
console.log(apiVersions.apiVersion);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
console.error(chalk.red(`Error: ${error}`));
|
|
20
|
+
}
|
|
21
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import { readYamlFile, inferResourceType } from '../config';
|
|
4
|
+
/**
|
|
5
|
+
* Handle the --config flag by parsing the YAML file and executing the appropriate command
|
|
6
|
+
* @param argv Command line arguments
|
|
7
|
+
* @param prompter Inquirerer instance
|
|
8
|
+
* @param options CLI options
|
|
9
|
+
* @param commandMap Map of available commands
|
|
10
|
+
*/
|
|
11
|
+
export default async (argv, prompter, options, commandMap) => {
|
|
12
|
+
if (!argv.config) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
const configPath = argv.config;
|
|
16
|
+
if (!fs.existsSync(configPath)) {
|
|
17
|
+
console.error(chalk.red(`Config file not found: ${configPath}`));
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const resource = readYamlFile(configPath);
|
|
22
|
+
const resourceType = inferResourceType(resource);
|
|
23
|
+
console.log(chalk.blue(`Detected resource type: ${resourceType}`));
|
|
24
|
+
let command;
|
|
25
|
+
command = 'apply';
|
|
26
|
+
const newArgv = {
|
|
27
|
+
...argv,
|
|
28
|
+
_: [configPath],
|
|
29
|
+
f: configPath
|
|
30
|
+
};
|
|
31
|
+
if (commandMap[command]) {
|
|
32
|
+
await commandMap[command](newArgv, prompter, options);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.error(chalk.red(`No command found for resource type: ${resourceType}`));
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error(chalk.red(`Error processing config file: ${error}`));
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { KubernetesClient } from 'kubernetesjs';
|
|
3
|
+
import { getCurrentNamespace, setCurrentNamespace } from '../config';
|
|
4
|
+
async function promptNamespace(prompter, argv, client) {
|
|
5
|
+
try {
|
|
6
|
+
const namespaces = await client.listCoreV1Namespace({
|
|
7
|
+
query: {}
|
|
8
|
+
});
|
|
9
|
+
if (!namespaces.items || namespaces.items.length === 0) {
|
|
10
|
+
console.log(chalk.yellow('No namespaces found'));
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
const options = namespaces.items.map(ns => ({
|
|
14
|
+
name: ns.metadata.name,
|
|
15
|
+
value: ns.metadata.name
|
|
16
|
+
}));
|
|
17
|
+
const question = {
|
|
18
|
+
type: 'autocomplete',
|
|
19
|
+
name: 'namespace',
|
|
20
|
+
message: 'Select namespace',
|
|
21
|
+
options,
|
|
22
|
+
maxDisplayLines: 10,
|
|
23
|
+
required: true
|
|
24
|
+
};
|
|
25
|
+
const { namespace } = await prompter.prompt(argv, [question]);
|
|
26
|
+
return namespace;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error(chalk.red(`Error getting namespaces: ${error}`));
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export default async (argv, prompter, _options) => {
|
|
34
|
+
try {
|
|
35
|
+
const client = new KubernetesClient({
|
|
36
|
+
restEndpoint: argv.clientUrl
|
|
37
|
+
});
|
|
38
|
+
const subcommand = argv._?.[0];
|
|
39
|
+
if (subcommand === 'get-context') {
|
|
40
|
+
const namespace = getCurrentNamespace();
|
|
41
|
+
console.log(chalk.green(`Current namespace: ${namespace}`));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (subcommand === 'set-context') {
|
|
45
|
+
if (argv.current !== true) {
|
|
46
|
+
console.error(chalk.red('Missing --current flag'));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
let namespace = argv.namespace;
|
|
50
|
+
if (!namespace) {
|
|
51
|
+
namespace = await promptNamespace(prompter, argv, client);
|
|
52
|
+
if (!namespace) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
setCurrentNamespace(namespace);
|
|
57
|
+
console.log(chalk.green(`Namespace set to "${namespace}"`));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
console.log(chalk.blue('Available config commands:'));
|
|
61
|
+
console.log(' get-context Display the current context');
|
|
62
|
+
console.log(' set-context --current --namespace=<namespace> Set the current namespace');
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error(chalk.red(`Error: ${error}`));
|
|
66
|
+
}
|
|
67
|
+
};
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { KubernetesClient } from 'kubernetesjs';
|
|
3
|
+
import { getCurrentNamespace, readYamlFile } from '../config';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
async function promptResourceType(prompter, argv) {
|
|
6
|
+
const resourceTypes = [
|
|
7
|
+
'pod',
|
|
8
|
+
'service',
|
|
9
|
+
'deployment',
|
|
10
|
+
'replicaset',
|
|
11
|
+
'statefulset',
|
|
12
|
+
'daemonset',
|
|
13
|
+
'configmap',
|
|
14
|
+
'secret'
|
|
15
|
+
];
|
|
16
|
+
const question = {
|
|
17
|
+
type: 'autocomplete',
|
|
18
|
+
name: 'resourceType',
|
|
19
|
+
message: 'Select resource type to delete',
|
|
20
|
+
options: resourceTypes,
|
|
21
|
+
maxDisplayLines: 10,
|
|
22
|
+
required: true
|
|
23
|
+
};
|
|
24
|
+
const { resourceType } = await prompter.prompt(argv, [question]);
|
|
25
|
+
return resourceType;
|
|
26
|
+
}
|
|
27
|
+
async function promptResourceSelection(prompter, argv, resourceType, namespace, client) {
|
|
28
|
+
let resources = [];
|
|
29
|
+
switch (resourceType) {
|
|
30
|
+
case 'pod':
|
|
31
|
+
const pods = await client.listCoreV1NamespacedPod({
|
|
32
|
+
path: { namespace },
|
|
33
|
+
query: { limit: 100 }
|
|
34
|
+
});
|
|
35
|
+
resources = pods.items || [];
|
|
36
|
+
break;
|
|
37
|
+
case 'service':
|
|
38
|
+
const services = await client.listCoreV1NamespacedService({
|
|
39
|
+
path: { namespace },
|
|
40
|
+
query: { limit: 100 }
|
|
41
|
+
});
|
|
42
|
+
resources = services.items || [];
|
|
43
|
+
break;
|
|
44
|
+
case 'deployment':
|
|
45
|
+
const deployments = await client.listAppsV1NamespacedDeployment({
|
|
46
|
+
path: { namespace },
|
|
47
|
+
query: { limit: 100 }
|
|
48
|
+
});
|
|
49
|
+
resources = deployments.items || [];
|
|
50
|
+
break;
|
|
51
|
+
case 'configmap':
|
|
52
|
+
const configmaps = await client.listCoreV1NamespacedConfigMap({
|
|
53
|
+
path: { namespace },
|
|
54
|
+
query: { limit: 100 }
|
|
55
|
+
});
|
|
56
|
+
resources = configmaps.items || [];
|
|
57
|
+
break;
|
|
58
|
+
case 'secret':
|
|
59
|
+
const secrets = await client.listCoreV1NamespacedSecret({
|
|
60
|
+
path: { namespace },
|
|
61
|
+
query: { limit: 100 }
|
|
62
|
+
});
|
|
63
|
+
resources = secrets.items || [];
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
console.log(chalk.yellow(`Resource type '${resourceType}' not implemented yet for selection`));
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
if (resources.length === 0) {
|
|
70
|
+
console.log(chalk.yellow(`No ${resourceType}s found in namespace ${namespace}`));
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const options = resources.map(r => ({
|
|
74
|
+
name: r.metadata.name,
|
|
75
|
+
value: r.metadata.name
|
|
76
|
+
}));
|
|
77
|
+
const question = {
|
|
78
|
+
type: 'checkbox',
|
|
79
|
+
name: 'selectedResources',
|
|
80
|
+
message: `Select ${resourceType}(s) to delete`,
|
|
81
|
+
options,
|
|
82
|
+
maxDisplayLines: 10,
|
|
83
|
+
required: true
|
|
84
|
+
};
|
|
85
|
+
let selectedResources;
|
|
86
|
+
({ selectedResources } = await prompter.prompt(argv, [question]));
|
|
87
|
+
return selectedResources
|
|
88
|
+
.filter(res => res.selected)
|
|
89
|
+
.map(res => res.value);
|
|
90
|
+
}
|
|
91
|
+
async function deleteResource(client, resourceType, resourceName, namespace) {
|
|
92
|
+
try {
|
|
93
|
+
switch (resourceType) {
|
|
94
|
+
case 'pod':
|
|
95
|
+
await client.deleteCoreV1NamespacedPod({
|
|
96
|
+
path: {
|
|
97
|
+
namespace,
|
|
98
|
+
name: resourceName
|
|
99
|
+
},
|
|
100
|
+
query: {}
|
|
101
|
+
});
|
|
102
|
+
console.log(chalk.green(`Pod "${resourceName}" deleted successfully`));
|
|
103
|
+
break;
|
|
104
|
+
case 'service':
|
|
105
|
+
await client.deleteCoreV1NamespacedService({
|
|
106
|
+
path: {
|
|
107
|
+
namespace,
|
|
108
|
+
name: resourceName
|
|
109
|
+
},
|
|
110
|
+
query: {}
|
|
111
|
+
});
|
|
112
|
+
console.log(chalk.green(`Service "${resourceName}" deleted successfully`));
|
|
113
|
+
break;
|
|
114
|
+
case 'deployment':
|
|
115
|
+
await client.deleteAppsV1NamespacedDeployment({
|
|
116
|
+
path: {
|
|
117
|
+
namespace,
|
|
118
|
+
name: resourceName
|
|
119
|
+
},
|
|
120
|
+
query: {}
|
|
121
|
+
});
|
|
122
|
+
console.log(chalk.green(`Deployment "${resourceName}" deleted successfully`));
|
|
123
|
+
break;
|
|
124
|
+
case 'configmap':
|
|
125
|
+
await client.deleteCoreV1NamespacedConfigMap({
|
|
126
|
+
path: {
|
|
127
|
+
namespace,
|
|
128
|
+
name: resourceName
|
|
129
|
+
},
|
|
130
|
+
query: {}
|
|
131
|
+
});
|
|
132
|
+
console.log(chalk.green(`ConfigMap "${resourceName}" deleted successfully`));
|
|
133
|
+
break;
|
|
134
|
+
case 'secret':
|
|
135
|
+
await client.deleteCoreV1NamespacedSecret({
|
|
136
|
+
path: {
|
|
137
|
+
namespace,
|
|
138
|
+
name: resourceName
|
|
139
|
+
},
|
|
140
|
+
query: {}
|
|
141
|
+
});
|
|
142
|
+
console.log(chalk.green(`Secret "${resourceName}" deleted successfully`));
|
|
143
|
+
break;
|
|
144
|
+
default:
|
|
145
|
+
console.log(chalk.yellow(`Resource type '${resourceType}' not implemented yet for deletion`));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.error(chalk.red(`Error deleting ${resourceType} "${resourceName}": ${error}`));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async function deleteFromYaml(client, filePath, namespace) {
|
|
153
|
+
try {
|
|
154
|
+
const content = readYamlFile(filePath);
|
|
155
|
+
const resources = Array.isArray(content) ? content :
|
|
156
|
+
(content.kind === 'List' && Array.isArray(content.items)) ? content.items :
|
|
157
|
+
[content];
|
|
158
|
+
for (const resource of resources) {
|
|
159
|
+
const kind = resource.kind.toLowerCase();
|
|
160
|
+
const name = resource.metadata?.name;
|
|
161
|
+
const ns = resource.metadata?.namespace || namespace;
|
|
162
|
+
if (!name) {
|
|
163
|
+
console.error(chalk.red('Resource must have a name'));
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
await deleteResource(client, kind, name, ns);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
console.error(chalk.red(`Error processing YAML file: ${error}`));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
export default async (argv, prompter, _options) => {
|
|
174
|
+
try {
|
|
175
|
+
const client = new KubernetesClient({
|
|
176
|
+
restEndpoint: 'http://localhost:8001' // Default kube-proxy endpoint
|
|
177
|
+
});
|
|
178
|
+
const namespace = argv.n || argv.namespace || getCurrentNamespace();
|
|
179
|
+
if (argv.f || argv.filename) {
|
|
180
|
+
const filePath = argv.f || argv.filename;
|
|
181
|
+
if (!fs.existsSync(filePath)) {
|
|
182
|
+
console.error(chalk.red(`File not found: ${filePath}`));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
await deleteFromYaml(client, filePath, namespace);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const resourceType = argv._?.[0] || await promptResourceType(prompter, argv);
|
|
189
|
+
const resourceName = argv._?.[1];
|
|
190
|
+
if (resourceName) {
|
|
191
|
+
await deleteResource(client, resourceType, resourceName, namespace);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
const selectedResources = await promptResourceSelection(prompter, argv, resourceType, namespace, client);
|
|
195
|
+
if (selectedResources.length === 0) {
|
|
196
|
+
console.log(chalk.yellow('No resources selected for deletion'));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const confirmQuestion = {
|
|
200
|
+
type: 'confirm',
|
|
201
|
+
name: 'confirmDelete',
|
|
202
|
+
message: `Are you sure you want to delete ${selectedResources.length} ${resourceType}(s)?`,
|
|
203
|
+
required: true
|
|
204
|
+
};
|
|
205
|
+
const { confirmDelete } = await prompter.prompt(argv, [confirmQuestion]);
|
|
206
|
+
if (!confirmDelete) {
|
|
207
|
+
console.log(chalk.yellow('Deletion cancelled'));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
for (const resource of selectedResources) {
|
|
211
|
+
await deleteResource(client, resourceType, resource, namespace);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
console.error(chalk.red(`Error: ${error}`));
|
|
217
|
+
}
|
|
218
|
+
};
|