@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.
Files changed (59) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +54 -55
  3. package/commands/apply.d.ts +4 -0
  4. package/commands/apply.js +171 -0
  5. package/commands/cluster-info.d.ts +4 -0
  6. package/commands/cluster-info.js +26 -0
  7. package/commands/config-handler.d.ts +11 -0
  8. package/commands/config-handler.js +81 -0
  9. package/commands/config.d.ts +4 -0
  10. package/commands/config.js +72 -0
  11. package/commands/delete.d.ts +4 -0
  12. package/commands/delete.js +256 -0
  13. package/commands/deploy.d.ts +6 -0
  14. package/commands/deploy.js +209 -0
  15. package/commands/describe.d.ts +4 -0
  16. package/commands/describe.js +216 -0
  17. package/commands/exec.d.ts +4 -0
  18. package/commands/exec.js +145 -0
  19. package/commands/get.d.ts +4 -0
  20. package/commands/get.js +164 -0
  21. package/commands/logs.d.ts +4 -0
  22. package/commands/logs.js +110 -0
  23. package/commands/port-forward.d.ts +4 -0
  24. package/commands/port-forward.js +143 -0
  25. package/commands.d.ts +3 -0
  26. package/commands.js +93 -0
  27. package/config.d.ts +22 -0
  28. package/config.js +113 -0
  29. package/esm/commands/apply.js +133 -0
  30. package/esm/commands/cluster-info.js +21 -0
  31. package/esm/commands/config-handler.js +43 -0
  32. package/esm/commands/config.js +67 -0
  33. package/esm/commands/delete.js +218 -0
  34. package/esm/commands/deploy.js +207 -0
  35. package/esm/commands/describe.js +211 -0
  36. package/esm/commands/exec.js +140 -0
  37. package/esm/commands/get.js +159 -0
  38. package/esm/commands/logs.js +105 -0
  39. package/esm/commands/port-forward.js +138 -0
  40. package/esm/commands.js +86 -0
  41. package/esm/config.js +74 -0
  42. package/esm/index.js +19 -0
  43. package/esm/package.js +26 -0
  44. package/esm/utils.js +49 -0
  45. package/index.d.ts +3 -0
  46. package/index.js +22 -0
  47. package/package.d.ts +1 -0
  48. package/package.js +29 -0
  49. package/package.json +37 -61
  50. package/utils.d.ts +11 -0
  51. package/utils.js +58 -0
  52. package/main/client.js +0 -156
  53. package/main/index.js +0 -2598
  54. package/module/client.js +0 -129
  55. package/module/index.js +0 -2594
  56. package/src/client.ts +0 -156
  57. package/src/index.ts +0 -14187
  58. package/types/client.d.ts +0 -31
  59. package/types/index.d.ts +0 -11331
@@ -0,0 +1,4 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ import { ParsedArgs } from 'minimist';
3
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<void>;
4
+ export default _default;
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const chalk_1 = __importDefault(require("chalk"));
7
+ const kubernetesjs_1 = require("kubernetesjs");
8
+ const config_1 = require("../config");
9
+ const child_process_1 = require("child_process");
10
+ async function promptPodName(prompter, argv, namespace, client) {
11
+ try {
12
+ const pods = await client.listCoreV1NamespacedPod({
13
+ path: { namespace },
14
+ query: { limit: 100 }
15
+ });
16
+ if (!pods.items || pods.items.length === 0) {
17
+ console.log(chalk_1.default.yellow(`No pods found in namespace ${namespace}`));
18
+ return '';
19
+ }
20
+ const options = pods.items.map(pod => ({
21
+ name: pod.metadata.name,
22
+ value: pod.metadata.name
23
+ }));
24
+ const question = {
25
+ type: 'autocomplete',
26
+ name: 'podName',
27
+ message: 'Select pod',
28
+ options,
29
+ maxDisplayLines: 10,
30
+ required: true
31
+ };
32
+ const { podName } = await prompter.prompt(argv, [question]);
33
+ return podName;
34
+ }
35
+ catch (error) {
36
+ console.error(chalk_1.default.red(`Error getting pods: ${error}`));
37
+ return '';
38
+ }
39
+ }
40
+ async function promptContainerName(prompter, argv, namespace, podName, client) {
41
+ try {
42
+ const pod = await client.readCoreV1NamespacedPod({
43
+ path: {
44
+ namespace,
45
+ name: podName
46
+ },
47
+ query: {}
48
+ });
49
+ if (!pod.spec || !pod.spec.containers || pod.spec.containers.length === 0) {
50
+ console.log(chalk_1.default.yellow(`No containers found in pod ${podName}`));
51
+ return '';
52
+ }
53
+ if (pod.spec.containers.length === 1) {
54
+ return pod.spec.containers[0].name;
55
+ }
56
+ const options = pod.spec.containers.map(container => ({
57
+ name: container.name,
58
+ value: container.name
59
+ }));
60
+ const question = {
61
+ type: 'autocomplete',
62
+ name: 'containerName',
63
+ message: 'Select container',
64
+ options,
65
+ maxDisplayLines: 10,
66
+ required: true
67
+ };
68
+ const { containerName } = await prompter.prompt(argv, [question]);
69
+ return containerName;
70
+ }
71
+ catch (error) {
72
+ console.error(chalk_1.default.red(`Error getting containers: ${error}`));
73
+ return '';
74
+ }
75
+ }
76
+ async function execInPod(namespace, podName, containerName, command) {
77
+ console.log(chalk_1.default.blue(`Executing command in ${containerName ? 'container ' + containerName + ' of ' : ''}pod ${podName} in namespace ${namespace}...`));
78
+ const kubectlArgs = [
79
+ 'exec',
80
+ '-it',
81
+ '-n', namespace,
82
+ podName
83
+ ];
84
+ if (containerName) {
85
+ kubectlArgs.push('-c', containerName);
86
+ }
87
+ kubectlArgs.push('--', ...command);
88
+ const kubectl = (0, child_process_1.spawn)('kubectl', kubectlArgs, {
89
+ stdio: 'inherit',
90
+ shell: true
91
+ });
92
+ return new Promise((resolve, reject) => {
93
+ kubectl.on('close', (code) => {
94
+ if (code === 0) {
95
+ resolve();
96
+ }
97
+ else {
98
+ reject(new Error(`kubectl exec exited with code ${code}`));
99
+ }
100
+ });
101
+ kubectl.on('error', (error) => {
102
+ reject(error);
103
+ });
104
+ });
105
+ }
106
+ exports.default = async (argv, prompter, _options) => {
107
+ try {
108
+ const client = new kubernetesjs_1.KubernetesClient({
109
+ restEndpoint: argv.clientUrl
110
+ });
111
+ const namespace = argv.n || argv.namespace || (0, config_1.getCurrentNamespace)();
112
+ const podName = argv._?.[0] || await promptPodName(prompter, argv, namespace, client);
113
+ if (!podName) {
114
+ return;
115
+ }
116
+ let containerName = argv.c || argv.container;
117
+ if (!containerName) {
118
+ containerName = await promptContainerName(prompter, argv, namespace, podName, client);
119
+ if (!containerName) {
120
+ return;
121
+ }
122
+ }
123
+ let command = [];
124
+ const dashIndex = argv._.findIndex(arg => arg === '--');
125
+ if (dashIndex !== -1 && dashIndex < argv._.length - 1) {
126
+ command = argv._.slice(dashIndex + 1);
127
+ }
128
+ else {
129
+ const commandQuestion = {
130
+ type: 'text',
131
+ name: 'command',
132
+ message: 'Enter command to execute',
133
+ required: true,
134
+ default: '/bin/sh',
135
+ useDefault: true
136
+ };
137
+ const { command: cmd } = await prompter.prompt(argv, [commandQuestion]);
138
+ command = cmd.split(' ');
139
+ }
140
+ await execInPod(namespace, podName, containerName, command);
141
+ }
142
+ catch (error) {
143
+ console.error(chalk_1.default.red(`Error: ${error}`));
144
+ }
145
+ };
@@ -0,0 +1,4 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ import { ParsedArgs } from 'minimist';
3
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<void>;
4
+ export default _default;
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const chalk_1 = __importDefault(require("chalk"));
7
+ const kubernetesjs_1 = require("kubernetesjs");
8
+ const config_1 = require("../config");
9
+ async function promptResourceType(prompter, argv) {
10
+ const resourceTypes = [
11
+ 'pods',
12
+ 'services',
13
+ 'deployments',
14
+ 'replicasets',
15
+ 'statefulsets',
16
+ 'daemonsets',
17
+ 'configmaps',
18
+ 'secrets',
19
+ 'namespaces',
20
+ 'all'
21
+ ];
22
+ const question = {
23
+ type: 'autocomplete',
24
+ name: 'resourceType',
25
+ message: 'Select resource type',
26
+ options: resourceTypes,
27
+ maxDisplayLines: 10,
28
+ required: true
29
+ };
30
+ const { resourceType } = await prompter.prompt(argv, [question]);
31
+ return resourceType;
32
+ }
33
+ function formatPodData(pod) {
34
+ const name = pod.metadata.name;
35
+ const ready = `${pod.status.containerStatuses?.filter((c) => c.ready).length || 0}/${pod.status.containerStatuses?.length || 0}`;
36
+ const status = pod.status.phase;
37
+ const restarts = pod.status.containerStatuses?.reduce((sum, c) => sum + c.restartCount, 0) || 0;
38
+ const age = new Date(pod.metadata.creationTimestamp).toLocaleString();
39
+ console.log(chalk_1.default.green(name.padEnd(50)) +
40
+ ready.padEnd(10) +
41
+ status.padEnd(15) +
42
+ restarts.toString().padEnd(10) +
43
+ age);
44
+ }
45
+ function formatServiceData(service) {
46
+ const name = service.metadata.name;
47
+ const type = service.spec.type;
48
+ const clusterIP = service.spec.clusterIP;
49
+ const externalIP = service.spec.externalIPs?.join(',') || '<none>';
50
+ const ports = service.spec.ports?.map((p) => `${p.port}:${p.targetPort}`).join(',') || '<none>';
51
+ const age = new Date(service.metadata.creationTimestamp).toLocaleString();
52
+ console.log(chalk_1.default.green(name.padEnd(30)) +
53
+ type.padEnd(15) +
54
+ clusterIP.padEnd(20) +
55
+ externalIP.padEnd(20) +
56
+ ports.padEnd(20) +
57
+ age);
58
+ }
59
+ function formatDeploymentData(deployment) {
60
+ const name = deployment.metadata.name;
61
+ const ready = `${deployment.status.readyReplicas || 0}/${deployment.status.replicas || 0}`;
62
+ const upToDate = deployment.status.updatedReplicas || 0;
63
+ const available = deployment.status.availableReplicas || 0;
64
+ const age = new Date(deployment.metadata.creationTimestamp).toLocaleString();
65
+ console.log(chalk_1.default.green(name.padEnd(30)) +
66
+ ready.padEnd(10) +
67
+ upToDate.toString().padEnd(10) +
68
+ available.toString().padEnd(10) +
69
+ age);
70
+ }
71
+ async function getAllResources(client, namespace) {
72
+ try {
73
+ const pods = await client.listCoreV1NamespacedPod({
74
+ path: { namespace },
75
+ query: { limit: 100 }
76
+ });
77
+ if (pods.items && pods.items.length > 0) {
78
+ console.log(chalk_1.default.bold('\nPODS:'));
79
+ console.log(chalk_1.default.bold('NAME'.padEnd(50) + 'READY'.padEnd(10) + 'STATUS'.padEnd(15) + 'RESTARTS'.padEnd(10) + 'AGE'));
80
+ pods.items.forEach(formatPodData);
81
+ }
82
+ const services = await client.listCoreV1NamespacedService({
83
+ path: { namespace },
84
+ query: { limit: 100 }
85
+ });
86
+ if (services.items && services.items.length > 0) {
87
+ console.log(chalk_1.default.bold('\nSERVICES:'));
88
+ console.log(chalk_1.default.bold('NAME'.padEnd(30) + 'TYPE'.padEnd(15) + 'CLUSTER-IP'.padEnd(20) + 'EXTERNAL-IP'.padEnd(20) + 'PORT(S)'.padEnd(20) + 'AGE'));
89
+ services.items.forEach(formatServiceData);
90
+ }
91
+ const deployments = await client.listAppsV1NamespacedDeployment({
92
+ path: { namespace },
93
+ query: { limit: 100 }
94
+ });
95
+ if (deployments.items && deployments.items.length > 0) {
96
+ console.log(chalk_1.default.bold('\nDEPLOYMENTS:'));
97
+ console.log(chalk_1.default.bold('NAME'.padEnd(30) + 'READY'.padEnd(10) + 'UP-TO-DATE'.padEnd(10) + 'AVAILABLE'.padEnd(10) + 'AGE'));
98
+ deployments.items.forEach(formatDeploymentData);
99
+ }
100
+ }
101
+ catch (error) {
102
+ console.error(chalk_1.default.red(`Error getting resources: ${error}`));
103
+ }
104
+ }
105
+ exports.default = async (argv, prompter, _options) => {
106
+ try {
107
+ const client = new kubernetesjs_1.KubernetesClient({
108
+ restEndpoint: argv.clientUrl
109
+ });
110
+ const namespace = argv.n || argv.namespace || (0, config_1.getCurrentNamespace)();
111
+ const resourceType = argv._?.[0] || await promptResourceType(prompter, argv);
112
+ console.log(chalk_1.default.blue(`Getting ${resourceType} in namespace ${namespace}...`));
113
+ if (resourceType === 'all') {
114
+ await getAllResources(client, namespace);
115
+ return;
116
+ }
117
+ switch (resourceType) {
118
+ case 'pods':
119
+ const pods = await client.listCoreV1NamespacedPod({
120
+ path: { namespace },
121
+ query: { limit: 100 }
122
+ });
123
+ console.log(chalk_1.default.bold('NAME'.padEnd(50) + 'READY'.padEnd(10) + 'STATUS'.padEnd(15) + 'RESTARTS'.padEnd(10) + 'AGE'));
124
+ if (pods.items && pods.items.length > 0) {
125
+ pods.items.forEach(formatPodData);
126
+ }
127
+ else {
128
+ console.log(chalk_1.default.yellow('No pods found'));
129
+ }
130
+ break;
131
+ case 'services':
132
+ const services = await client.listCoreV1NamespacedService({
133
+ path: { namespace },
134
+ query: { limit: 100 }
135
+ });
136
+ console.log(chalk_1.default.bold('NAME'.padEnd(30) + 'TYPE'.padEnd(15) + 'CLUSTER-IP'.padEnd(20) + 'EXTERNAL-IP'.padEnd(20) + 'PORT(S)'.padEnd(20) + 'AGE'));
137
+ if (services.items && services.items.length > 0) {
138
+ services.items.forEach(formatServiceData);
139
+ }
140
+ else {
141
+ console.log(chalk_1.default.yellow('No services found'));
142
+ }
143
+ break;
144
+ case 'deployments':
145
+ const deployments = await client.listAppsV1NamespacedDeployment({
146
+ path: { namespace },
147
+ query: { limit: 100 }
148
+ });
149
+ console.log(chalk_1.default.bold('NAME'.padEnd(30) + 'READY'.padEnd(10) + 'UP-TO-DATE'.padEnd(10) + 'AVAILABLE'.padEnd(10) + 'AGE'));
150
+ if (deployments.items && deployments.items.length > 0) {
151
+ deployments.items.forEach(formatDeploymentData);
152
+ }
153
+ else {
154
+ console.log(chalk_1.default.yellow('No deployments found'));
155
+ }
156
+ break;
157
+ default:
158
+ console.log(chalk_1.default.yellow(`Resource type '${resourceType}' not implemented yet`));
159
+ }
160
+ }
161
+ catch (error) {
162
+ console.error(chalk_1.default.red(`Error: ${error}`));
163
+ }
164
+ };
@@ -0,0 +1,4 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ import { ParsedArgs } from 'minimist';
3
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<void>;
4
+ export default _default;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const chalk_1 = __importDefault(require("chalk"));
7
+ const kubernetesjs_1 = require("kubernetesjs");
8
+ const config_1 = require("../config");
9
+ async function promptPodName(prompter, argv, namespace, client) {
10
+ try {
11
+ const pods = await client.listCoreV1NamespacedPod({
12
+ path: { namespace },
13
+ query: { limit: 100 }
14
+ });
15
+ if (!pods.items || pods.items.length === 0) {
16
+ console.log(chalk_1.default.yellow(`No pods found in namespace ${namespace}`));
17
+ return '';
18
+ }
19
+ const options = pods.items.map(pod => ({
20
+ name: pod.metadata.name,
21
+ value: pod.metadata.name
22
+ }));
23
+ const question = {
24
+ type: 'autocomplete',
25
+ name: 'podName',
26
+ message: 'Select pod',
27
+ options,
28
+ maxDisplayLines: 10,
29
+ required: true
30
+ };
31
+ const { podName } = await prompter.prompt(argv, [question]);
32
+ return podName;
33
+ }
34
+ catch (error) {
35
+ console.error(chalk_1.default.red(`Error getting pods: ${error}`));
36
+ return '';
37
+ }
38
+ }
39
+ async function promptContainerName(prompter, argv, namespace, podName, client) {
40
+ try {
41
+ const pod = await client.readCoreV1NamespacedPod({
42
+ path: {
43
+ namespace,
44
+ name: podName
45
+ },
46
+ query: {}
47
+ });
48
+ if (!pod.spec || !pod.spec.containers || pod.spec.containers.length === 0) {
49
+ console.log(chalk_1.default.yellow(`No containers found in pod ${podName}`));
50
+ return '';
51
+ }
52
+ if (pod.spec.containers.length === 1) {
53
+ return pod.spec.containers[0].name;
54
+ }
55
+ const options = pod.spec.containers.map(container => ({
56
+ name: container.name,
57
+ value: container.name
58
+ }));
59
+ const question = {
60
+ type: 'autocomplete',
61
+ name: 'containerName',
62
+ message: 'Select container',
63
+ options,
64
+ maxDisplayLines: 10,
65
+ required: true
66
+ };
67
+ const { containerName } = await prompter.prompt(argv, [question]);
68
+ return containerName;
69
+ }
70
+ catch (error) {
71
+ console.error(chalk_1.default.red(`Error getting containers: ${error}`));
72
+ return '';
73
+ }
74
+ }
75
+ exports.default = async (argv, prompter, _options) => {
76
+ try {
77
+ const client = new kubernetesjs_1.KubernetesClient({
78
+ restEndpoint: argv.clientUrl
79
+ });
80
+ const namespace = argv.n || argv.namespace || (0, config_1.getCurrentNamespace)();
81
+ const podName = argv._?.[0] || await promptPodName(prompter, argv, namespace, client);
82
+ if (!podName) {
83
+ return;
84
+ }
85
+ let containerName = argv.c || argv.container;
86
+ if (!containerName) {
87
+ containerName = await promptContainerName(prompter, argv, namespace, podName, client);
88
+ if (!containerName) {
89
+ return;
90
+ }
91
+ }
92
+ console.log(chalk_1.default.blue(`Getting logs for ${containerName ? 'container ' + containerName + ' in ' : ''}pod ${podName} in namespace ${namespace}...`));
93
+ const logs = await client.readCoreV1NamespacedPodLog({
94
+ path: {
95
+ namespace,
96
+ name: podName
97
+ },
98
+ query: {
99
+ container: containerName,
100
+ tailLines: argv.tail ? parseInt(argv.tail, 10) : undefined,
101
+ follow: false,
102
+ previous: argv.previous === true
103
+ }
104
+ });
105
+ console.log(logs);
106
+ }
107
+ catch (error) {
108
+ console.error(chalk_1.default.red(`Error: ${error}`));
109
+ }
110
+ };
@@ -0,0 +1,4 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ import { ParsedArgs } from 'minimist';
3
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<void>;
4
+ export default _default;
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const chalk_1 = __importDefault(require("chalk"));
7
+ const kubernetesjs_1 = require("kubernetesjs");
8
+ const config_1 = require("../config");
9
+ const child_process_1 = require("child_process");
10
+ async function promptServiceName(prompter, argv, namespace, client) {
11
+ try {
12
+ const services = await client.listCoreV1NamespacedService({
13
+ path: { namespace },
14
+ query: { limit: 100 }
15
+ });
16
+ if (!services.items || services.items.length === 0) {
17
+ console.log(chalk_1.default.yellow(`No services found in namespace ${namespace}`));
18
+ return '';
19
+ }
20
+ const options = services.items.map(service => ({
21
+ name: service.metadata.name,
22
+ value: service.metadata.name
23
+ }));
24
+ const question = {
25
+ type: 'autocomplete',
26
+ name: 'serviceName',
27
+ message: 'Select service',
28
+ options,
29
+ maxDisplayLines: 10,
30
+ required: true
31
+ };
32
+ const { serviceName } = await prompter.prompt(argv, [question]);
33
+ return serviceName;
34
+ }
35
+ catch (error) {
36
+ console.error(chalk_1.default.red(`Error getting services: ${error}`));
37
+ return '';
38
+ }
39
+ }
40
+ async function promptPortMapping(prompter, argv, namespace, serviceName, client) {
41
+ try {
42
+ const service = await client.readCoreV1NamespacedService({
43
+ path: {
44
+ namespace,
45
+ name: serviceName
46
+ },
47
+ query: {}
48
+ });
49
+ if (!service.spec || !service.spec.ports || service.spec.ports.length === 0) {
50
+ console.log(chalk_1.default.yellow(`No ports found in service ${serviceName}`));
51
+ return '';
52
+ }
53
+ if (service.spec.ports.length === 1) {
54
+ const port = service.spec.ports[0];
55
+ const localPort = port.port;
56
+ const remotePort = port.targetPort || port.port;
57
+ const confirmQuestion = {
58
+ type: 'confirm',
59
+ name: 'confirmPortMapping',
60
+ message: `Use port mapping ${localPort}:${remotePort}?`,
61
+ required: true
62
+ };
63
+ const { confirmPortMapping } = await prompter.prompt(argv, [confirmQuestion]);
64
+ if (confirmPortMapping) {
65
+ return `${localPort}:${remotePort}`;
66
+ }
67
+ }
68
+ const portMappingQuestion = {
69
+ type: 'text',
70
+ name: 'portMapping',
71
+ message: 'Enter port mapping (local:remote)',
72
+ required: true
73
+ };
74
+ const { portMapping } = await prompter.prompt(argv, [portMappingQuestion]);
75
+ return portMapping;
76
+ }
77
+ catch (error) {
78
+ console.error(chalk_1.default.red(`Error getting service ports: ${error}`));
79
+ return '';
80
+ }
81
+ }
82
+ async function portForward(namespace, resourceType, resourceName, portMapping) {
83
+ console.log(chalk_1.default.blue(`Forwarding ports ${portMapping} to ${resourceType}/${resourceName} in namespace ${namespace}...`));
84
+ console.log(chalk_1.default.yellow('Press Ctrl+C to stop port forwarding'));
85
+ const kubectlArgs = [
86
+ 'port-forward',
87
+ '-n', namespace,
88
+ `${resourceType}/${resourceName}`,
89
+ portMapping
90
+ ];
91
+ const kubectl = (0, child_process_1.spawn)('kubectl', kubectlArgs, {
92
+ stdio: 'inherit',
93
+ shell: true
94
+ });
95
+ return new Promise((resolve, reject) => {
96
+ kubectl.on('close', (code) => {
97
+ if (code === 0 || code === 130) { // 130 is the exit code when terminated by Ctrl+C
98
+ resolve();
99
+ }
100
+ else {
101
+ reject(new Error(`kubectl port-forward exited with code ${code}`));
102
+ }
103
+ });
104
+ kubectl.on('error', (error) => {
105
+ reject(error);
106
+ });
107
+ });
108
+ }
109
+ exports.default = async (argv, prompter, _options) => {
110
+ try {
111
+ const client = new kubernetesjs_1.KubernetesClient({
112
+ restEndpoint: argv.clientUrl
113
+ });
114
+ const namespace = argv.n || argv.namespace || (0, config_1.getCurrentNamespace)();
115
+ let resourceType = 'svc';
116
+ let resourceName = '';
117
+ if (argv._?.[0]) {
118
+ const resourceArg = argv._[0];
119
+ if (resourceArg.includes('/')) {
120
+ const [type, name] = resourceArg.split('/');
121
+ resourceType = type;
122
+ resourceName = name;
123
+ }
124
+ else {
125
+ resourceName = resourceArg;
126
+ }
127
+ }
128
+ if (!resourceName) {
129
+ resourceName = await promptServiceName(prompter, argv, namespace, client);
130
+ if (!resourceName) {
131
+ return;
132
+ }
133
+ }
134
+ const portMapping = argv._?.[1] || await promptPortMapping(prompter, argv, namespace, resourceName, client);
135
+ if (!portMapping) {
136
+ return;
137
+ }
138
+ await portForward(namespace, resourceType, resourceName, portMapping);
139
+ }
140
+ catch (error) {
141
+ console.error(chalk_1.default.red(`Error: ${error}`));
142
+ }
143
+ };
package/commands.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { CLIOptions, Inquirerer } from 'inquirerer';
2
+ import { ParsedArgs } from 'minimist';
3
+ export declare const commands: (argv: Partial<ParsedArgs>, prompter: Inquirerer, options: CLIOptions) => Promise<Partial<ParsedArgs>>;
package/commands.js ADDED
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.commands = void 0;
7
+ const package_1 = require("./package");
8
+ const utils_1 = require("./utils");
9
+ // Commands
10
+ const deploy_1 = __importDefault(require("./commands/deploy"));
11
+ const get_1 = __importDefault(require("./commands/get"));
12
+ const describe_1 = __importDefault(require("./commands/describe"));
13
+ const logs_1 = __importDefault(require("./commands/logs"));
14
+ const apply_1 = __importDefault(require("./commands/apply"));
15
+ const delete_1 = __importDefault(require("./commands/delete"));
16
+ const exec_1 = __importDefault(require("./commands/exec"));
17
+ const port_forward_1 = __importDefault(require("./commands/port-forward"));
18
+ const cluster_info_1 = __importDefault(require("./commands/cluster-info"));
19
+ const config_1 = __importDefault(require("./commands/config"));
20
+ const commandMap = {
21
+ deploy: deploy_1.default,
22
+ get: get_1.default,
23
+ describe: describe_1.default,
24
+ logs: logs_1.default,
25
+ apply: apply_1.default,
26
+ delete: delete_1.default,
27
+ exec: exec_1.default,
28
+ 'port-forward': port_forward_1.default,
29
+ 'cluster-info': cluster_info_1.default,
30
+ config: config_1.default
31
+ };
32
+ const config_handler_1 = __importDefault(require("./commands/config-handler"));
33
+ const commands = async (argv, prompter, options) => {
34
+ if (argv.version || argv.v) {
35
+ const pkg = (0, package_1.readAndParsePackageJson)();
36
+ console.log(pkg.version);
37
+ process.exit(0);
38
+ }
39
+ if (argv.config) {
40
+ const handled = await (0, config_handler_1.default)(argv, prompter, options, commandMap);
41
+ if (handled) {
42
+ prompter.close();
43
+ return argv;
44
+ }
45
+ }
46
+ let { first: command, newArgv } = (0, utils_1.extractFirst)(argv);
47
+ // Show usage if explicitly requested
48
+ if (argv.help || argv.h || command === 'help') {
49
+ console.log(utils_1.usageText);
50
+ process.exit(0);
51
+ }
52
+ // Prompt if no command provided
53
+ if (!command) {
54
+ const answer = await prompter.prompt(argv, [
55
+ {
56
+ type: 'autocomplete',
57
+ name: 'command',
58
+ message: 'What do you want to do?',
59
+ options: Object.keys(commandMap)
60
+ }
61
+ ]);
62
+ command = answer.command;
63
+ }
64
+ // Prompt for working directory and client URL
65
+ newArgv = await prompter.prompt(newArgv, [
66
+ {
67
+ type: 'text',
68
+ name: 'cwd',
69
+ message: 'Working directory',
70
+ required: false,
71
+ default: process.cwd(),
72
+ useDefault: true
73
+ },
74
+ {
75
+ type: 'text',
76
+ name: 'clientUrl',
77
+ message: 'Kubernetes API URL',
78
+ required: false,
79
+ default: 'http://127.0.0.1:8001',
80
+ useDefault: true
81
+ }
82
+ ]);
83
+ const commandFn = commandMap[command];
84
+ if (!commandFn) {
85
+ console.error(`Unknown command: ${command}`);
86
+ console.log(utils_1.usageText);
87
+ process.exit(1);
88
+ }
89
+ await commandFn(newArgv, prompter, options);
90
+ prompter.close();
91
+ return argv;
92
+ };
93
+ exports.commands = commands;