@chabokan.net/cli 0.8.10 → 0.9.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/README.md +520 -66
- package/dist/base.d.ts +34 -9
- package/dist/base.js +172 -20
- package/dist/commands/account/info.d.ts +12 -0
- package/dist/commands/account/info.js +40 -0
- package/dist/commands/account/list.d.ts +5 -1
- package/dist/commands/account/list.js +35 -16
- package/dist/commands/account/remove.d.ts +5 -1
- package/dist/commands/account/remove.js +30 -15
- package/dist/commands/account/use.d.ts +6 -2
- package/dist/commands/account/use.js +26 -15
- package/dist/commands/cloudserver/create.d.ts +40 -0
- package/dist/commands/cloudserver/create.js +242 -0
- package/dist/commands/cloudserver/delete.d.ts +14 -0
- package/dist/commands/cloudserver/delete.js +65 -0
- package/dist/commands/cloudserver/list.d.ts +12 -0
- package/dist/commands/cloudserver/list.js +46 -0
- package/dist/commands/cloudserver/restart.d.ts +13 -0
- package/dist/commands/cloudserver/restart.js +51 -0
- package/dist/commands/cloudserver/start.d.ts +13 -0
- package/dist/commands/cloudserver/start.js +51 -0
- package/dist/commands/cloudserver/stop.d.ts +13 -0
- package/dist/commands/cloudserver/stop.js +52 -0
- package/dist/commands/deploy.d.ts +16 -5
- package/dist/commands/deploy.js +182 -101
- package/dist/commands/login.d.ts +8 -4
- package/dist/commands/login.js +97 -49
- package/dist/commands/service/domain/add.d.ts +15 -0
- package/dist/commands/service/domain/add.js +74 -0
- package/dist/commands/service/domain/remove.d.ts +15 -0
- package/dist/commands/service/domain/remove.js +72 -0
- package/dist/commands/service/list.d.ts +5 -1
- package/dist/commands/service/list.js +41 -20
- package/dist/commands/service/logs.d.ts +7 -3
- package/dist/commands/service/logs.js +46 -34
- package/dist/commands/service/resize.d.ts +10 -6
- package/dist/commands/service/resize.js +94 -72
- package/dist/commands/service/restart.d.ts +7 -3
- package/dist/commands/service/restart.js +40 -31
- package/dist/commands/service/start.d.ts +7 -3
- package/dist/commands/service/start.js +41 -30
- package/dist/commands/service/stop.d.ts +7 -3
- package/dist/commands/service/stop.js +41 -30
- package/dist/commands/wallet/list.d.ts +12 -0
- package/dist/commands/wallet/list.js +41 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +7 -2
- package/dist/helper.d.ts +32 -9
- package/dist/helper.js +426 -49
- package/dist/types.d.ts +77 -0
- package/dist/types.js +2 -0
- package/dist/ui.d.ts +23 -0
- package/dist/ui.js +70 -0
- package/oclif.manifest.json +635 -25
- package/package.json +39 -35
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Command from "../../../base.js";
|
|
2
|
+
export default class ServiceDomainRemove extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: {
|
|
5
|
+
description: string;
|
|
6
|
+
command: string;
|
|
7
|
+
}[];
|
|
8
|
+
static flags: {
|
|
9
|
+
service: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
domain: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
help: import("@oclif/core/interfaces").BooleanFlag<void>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
send_request(cli: Command, selected_service: string, domain_name: string): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import Command from "../../../base.js";
|
|
3
|
+
import { handleApiError, logErrorDetails } from "../../../helper.js";
|
|
4
|
+
import * as ui from "../../../ui.js";
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
import axios from "axios";
|
|
7
|
+
export default class ServiceDomainRemove extends Command {
|
|
8
|
+
static description = 'disconnect a custom domain from a service';
|
|
9
|
+
static examples = [
|
|
10
|
+
{
|
|
11
|
+
description: 'Pick the service and enter the domain interactively',
|
|
12
|
+
command: '<%= config.bin %> service domain remove',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
description: 'Disconnect a domain in one non-interactive command',
|
|
16
|
+
command: '<%= config.bin %> service domain remove -s my-app -d www.example.com',
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
static flags = {
|
|
20
|
+
...Command.flags,
|
|
21
|
+
service: Flags.string({ char: 's', description: 'name of the service the domain is connected to' }),
|
|
22
|
+
domain: Flags.string({ char: 'd', description: 'domain name to disconnect' }),
|
|
23
|
+
};
|
|
24
|
+
async run() {
|
|
25
|
+
const { flags } = await this.parse(ServiceDomainRemove);
|
|
26
|
+
const cli = this;
|
|
27
|
+
await this.init_run();
|
|
28
|
+
if (!(await this.require_login())) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const selected_service = await this.select_service(flags.service, {}, 'Disconnect Domain');
|
|
32
|
+
if (!selected_service) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
let domain_name = flags.domain;
|
|
36
|
+
if (!domain_name) {
|
|
37
|
+
({ domain_name } = await inquirer.prompt({
|
|
38
|
+
type: 'input',
|
|
39
|
+
message: 'Domain name:',
|
|
40
|
+
name: 'domain_name',
|
|
41
|
+
validate(input) {
|
|
42
|
+
return input.trim().length > 0 || 'Domain name cannot be empty';
|
|
43
|
+
},
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
await this.send_request(cli, selected_service, domain_name.trim());
|
|
47
|
+
}
|
|
48
|
+
async send_request(cli, selected_service, domain_name) {
|
|
49
|
+
try {
|
|
50
|
+
const { data } = await axios.delete(`services/${selected_service}/domain/${domain_name}/`, this.axiosConfig);
|
|
51
|
+
if (data?.success === false) {
|
|
52
|
+
cli.log(ui.error(`Could not disconnect ${ui.value(domain_name)}. ${data.message || 'Check the domain name and try again.'}`));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
cli.log(ui.success(`Disconnected ${ui.value(domain_name)} from ${ui.value(selected_service)}.`));
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
const errorInfo = handleApiError(error, 'Failed to disconnect domain.', {
|
|
59
|
+
endpoint: `services/${selected_service}/domain/${domain_name}/`,
|
|
60
|
+
serviceName: selected_service,
|
|
61
|
+
operation: 'Disconnect Domain'
|
|
62
|
+
});
|
|
63
|
+
if (errorInfo.status === 404) {
|
|
64
|
+
cli.log(ui.error(`Domain ${ui.value(domain_name)} was not found on ${ui.value(selected_service)}.`));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
cli.log(ui.error(errorInfo.message));
|
|
68
|
+
}
|
|
69
|
+
logErrorDetails(errorInfo, cli);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import Command from "../../base.js";
|
|
2
2
|
export default class ServiceList extends Command {
|
|
3
3
|
static description: string;
|
|
4
|
+
static examples: {
|
|
5
|
+
description: string;
|
|
6
|
+
command: string;
|
|
7
|
+
}[];
|
|
4
8
|
static flags: {
|
|
5
|
-
help: import("@oclif/core/
|
|
9
|
+
help: import("@oclif/core/interfaces").BooleanFlag<void>;
|
|
6
10
|
};
|
|
7
11
|
run(): Promise<void>;
|
|
8
12
|
}
|
|
@@ -1,32 +1,53 @@
|
|
|
1
1
|
import Command from "../../base.js";
|
|
2
|
-
import {
|
|
2
|
+
import { printTable } from "@oclif/table";
|
|
3
|
+
import * as ui from "../../ui.js";
|
|
4
|
+
import { handleApiError, logErrorDetails } from "../../helper.js";
|
|
3
5
|
export default class ServiceList extends Command {
|
|
4
|
-
static description = "
|
|
6
|
+
static description = "list the services on your account";
|
|
7
|
+
static examples = [
|
|
8
|
+
{
|
|
9
|
+
description: 'List every service on the active account',
|
|
10
|
+
command: '<%= config.bin %> service list',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
description: 'Switch account first, then list that account’s services',
|
|
14
|
+
command: '<%= config.bin %> account use -u me@example.com && <%= config.bin %> service list',
|
|
15
|
+
},
|
|
16
|
+
];
|
|
5
17
|
static flags = {
|
|
6
18
|
...Command.flags,
|
|
7
19
|
};
|
|
8
20
|
async run() {
|
|
9
|
-
|
|
21
|
+
await this.parse(ServiceList);
|
|
10
22
|
const cli = this;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
try {
|
|
24
|
+
await this.init_run();
|
|
25
|
+
if (!(await this.require_login())) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const all_services = await this.get_services();
|
|
29
|
+
if (all_services.length === 0) {
|
|
30
|
+
cli.log(ui.info('You have no services yet.'));
|
|
31
|
+
cli.log(ui.hint('Create one at https://hub.chabokan.net, then come back here'));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const services_data = all_services.map((service) => ({
|
|
35
|
+
Service: service.value,
|
|
36
|
+
Platform: service.platform,
|
|
37
|
+
}));
|
|
38
|
+
printTable({
|
|
39
|
+
data: services_data,
|
|
40
|
+
columns: ["Service", "Platform"],
|
|
22
41
|
});
|
|
23
|
-
|
|
24
|
-
Name: {},
|
|
25
|
-
}, flags);
|
|
42
|
+
cli.log(ui.hint(`Act on one with ${ui.cmd('chabok service logs -s <name>')}, ${ui.cmd('restart')}, ${ui.cmd('stop')} …`));
|
|
26
43
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
44
|
+
catch (error) {
|
|
45
|
+
const errorInfo = handleApiError(error, 'Failed to fetch services list.', {
|
|
46
|
+
endpoint: 'services/',
|
|
47
|
+
operation: 'List Services'
|
|
48
|
+
});
|
|
49
|
+
cli.log(ui.error(errorInfo.message));
|
|
50
|
+
logErrorDetails(errorInfo, cli);
|
|
30
51
|
}
|
|
31
52
|
}
|
|
32
53
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import Command from "../../base.js";
|
|
2
2
|
export default class ServiceLogs extends Command {
|
|
3
3
|
static description: string;
|
|
4
|
+
static examples: {
|
|
5
|
+
description: string;
|
|
6
|
+
command: string;
|
|
7
|
+
}[];
|
|
4
8
|
static flags: {
|
|
5
|
-
service: import("@oclif/core/
|
|
6
|
-
help: import("@oclif/core/
|
|
9
|
+
service: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
help: import("@oclif/core/interfaces").BooleanFlag<void>;
|
|
7
11
|
};
|
|
8
12
|
run(): Promise<void>;
|
|
9
|
-
send_request(cli:
|
|
13
|
+
send_request(cli: Command, selected_service: string): Promise<void>;
|
|
10
14
|
}
|
|
@@ -1,59 +1,71 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import Command from "../../base.js";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import inquirer from 'inquirer';
|
|
3
|
+
import { handleApiError, logErrorDetails } from "../../helper.js";
|
|
4
|
+
import * as ui from "../../ui.js";
|
|
6
5
|
import axios from "axios";
|
|
7
6
|
export default class ServiceLogs extends Command {
|
|
8
|
-
static description = 'read latest logs from service';
|
|
7
|
+
static description = 'read the latest logs from a service';
|
|
8
|
+
static examples = [
|
|
9
|
+
{
|
|
10
|
+
description: 'Pick a service from an interactive list',
|
|
11
|
+
command: '<%= config.bin %> service logs',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
description: 'Read logs for a specific service',
|
|
15
|
+
command: '<%= config.bin %> service logs --service my-app',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
description: 'Search the logs for errors',
|
|
19
|
+
command: '<%= config.bin %> service logs -s my-app | grep -i error',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
description: 'Save the logs to a file',
|
|
23
|
+
command: '<%= config.bin %> service logs -s my-app > my-app.log',
|
|
24
|
+
},
|
|
25
|
+
];
|
|
9
26
|
static flags = {
|
|
10
27
|
...Command.flags,
|
|
11
|
-
service: Flags.string({ char: 's', description: 'service
|
|
28
|
+
service: Flags.string({ char: 's', description: 'name of the service to read logs from' }),
|
|
12
29
|
};
|
|
13
30
|
async run() {
|
|
14
|
-
const {
|
|
31
|
+
const { flags } = await this.parse(ServiceLogs);
|
|
15
32
|
const cli = this;
|
|
16
33
|
await this.init_run();
|
|
17
|
-
|
|
18
|
-
let selected_service = flags.service;
|
|
19
|
-
if (isEmptyObject(config_json.users)) {
|
|
20
|
-
cli.log(`${chalk.red('[Error]')} first you should login!`);
|
|
34
|
+
if (!(await this.require_login())) {
|
|
21
35
|
return;
|
|
22
36
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
let { service } = await inquirer.prompt({
|
|
27
|
-
type: 'list',
|
|
28
|
-
message: 'Please select a service:',
|
|
29
|
-
name: 'service',
|
|
30
|
-
choices: all_services
|
|
31
|
-
});
|
|
32
|
-
selected_service = service;
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
cli.log("first you should create service");
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
37
|
+
const selected_service = await this.select_service(flags.service, {}, 'Fetch Logs');
|
|
38
|
+
if (!selected_service) {
|
|
39
|
+
return;
|
|
38
40
|
}
|
|
39
41
|
await this.send_request(cli, selected_service);
|
|
40
42
|
}
|
|
41
43
|
async send_request(cli, selected_service) {
|
|
42
44
|
try {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
const { data } = await axios.get(`services/${selected_service}/logs/`, this.axiosConfig);
|
|
46
|
+
if (data.success && data.logs) {
|
|
47
|
+
// Logs go out verbatim so they stay pipeable into grep, tee and friends.
|
|
48
|
+
cli.log(data.logs);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
cli.log(ui.info(`No logs yet for ${ui.value(selected_service)}.`));
|
|
52
|
+
cli.log(ui.hint('A service that has just started may take a moment to produce output'));
|
|
48
53
|
}
|
|
49
54
|
}
|
|
50
|
-
catch (
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
catch (error) {
|
|
56
|
+
const errorInfo = handleApiError(error, 'Failed to fetch service logs.', {
|
|
57
|
+
endpoint: `services/${selected_service}/logs/`,
|
|
58
|
+
serviceName: selected_service,
|
|
59
|
+
operation: 'Fetch Logs'
|
|
60
|
+
});
|
|
61
|
+
if (errorInfo.status === 404) {
|
|
62
|
+
cli.log(ui.error(`Service ${ui.value(selected_service)} was not found.`));
|
|
63
|
+
cli.log(ui.hint(`Check the available names with ${ui.cmd('chabok service list')}`));
|
|
53
64
|
}
|
|
54
65
|
else {
|
|
55
|
-
|
|
66
|
+
cli.log(ui.error(errorInfo.message));
|
|
56
67
|
}
|
|
68
|
+
logErrorDetails(errorInfo, cli);
|
|
57
69
|
}
|
|
58
70
|
}
|
|
59
71
|
}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import Command from "../../base.js";
|
|
2
2
|
export default class ServiceResize extends Command {
|
|
3
3
|
static description: string;
|
|
4
|
+
static examples: {
|
|
5
|
+
description: string;
|
|
6
|
+
command: string;
|
|
7
|
+
}[];
|
|
4
8
|
static flags: {
|
|
5
|
-
service: import("@oclif/core/
|
|
6
|
-
ram: import("@oclif/core/
|
|
7
|
-
cpu: import("@oclif/core/
|
|
8
|
-
disk: import("@oclif/core/
|
|
9
|
-
help: import("@oclif/core/
|
|
9
|
+
service: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
ram: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
cpu: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
disk: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
help: import("@oclif/core/interfaces").BooleanFlag<void>;
|
|
10
14
|
};
|
|
11
15
|
run(): Promise<void>;
|
|
12
|
-
send_request(cli:
|
|
16
|
+
send_request(cli: Command, selected_service: string, ram: string, cpu: string, disk: string): Promise<void>;
|
|
13
17
|
}
|
|
@@ -1,130 +1,152 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import Command from "../../base.js";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
3
|
+
import { handleApiError, logErrorDetails } from "../../helper.js";
|
|
4
|
+
import * as ui from "../../ui.js";
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
6
|
import axios from "axios";
|
|
7
7
|
export default class ServiceResize extends Command {
|
|
8
|
-
static description = '
|
|
8
|
+
static description = 'change the RAM, CPU and disk allocated to a service';
|
|
9
|
+
static examples = [
|
|
10
|
+
{
|
|
11
|
+
description: 'Choose the service and every resource interactively',
|
|
12
|
+
command: '<%= config.bin %> service resize',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
description: 'Resize a service in one non-interactive command',
|
|
16
|
+
command: '<%= config.bin %> service resize -s my-app --ram 2 --cpu 1 --disk 10',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
description: 'Set only the RAM and pick the rest from the prompts',
|
|
20
|
+
command: '<%= config.bin %> service resize -s my-app --ram 4',
|
|
21
|
+
},
|
|
22
|
+
];
|
|
9
23
|
static flags = {
|
|
10
24
|
...Command.flags,
|
|
11
|
-
service: Flags.string({ char: 's', description: 'service
|
|
12
|
-
ram: Flags.string({ char: 'r', description: 'RAM' }),
|
|
13
|
-
cpu: Flags.string({ char: 'c', description: 'CPU' }),
|
|
14
|
-
disk: Flags.string({ char: 'd', description: '
|
|
25
|
+
service: Flags.string({ char: 's', description: 'name of the service to resize' }),
|
|
26
|
+
ram: Flags.string({ char: 'r', description: 'RAM in GB, in steps of 0.5 (e.g. 0.5, 1, 2)' }),
|
|
27
|
+
cpu: Flags.string({ char: 'c', description: 'CPU cores, in steps of 0.5 (e.g. 0.5, 1, 2)' }),
|
|
28
|
+
disk: Flags.string({ char: 'd', description: 'disk in GB, in steps of 5 (e.g. 5, 10, 30)' }),
|
|
15
29
|
};
|
|
16
30
|
async run() {
|
|
17
|
-
const {
|
|
31
|
+
const { flags } = await this.parse(ServiceResize);
|
|
18
32
|
const cli = this;
|
|
19
33
|
await this.init_run();
|
|
20
|
-
const config_json = await this.read_config();
|
|
21
|
-
let selected_service = flags.service;
|
|
22
34
|
let selected_ram = flags.ram;
|
|
23
35
|
let selected_cpu = flags.cpu;
|
|
24
36
|
let selected_disk = flags.disk;
|
|
25
|
-
if (
|
|
26
|
-
cli.log(`${chalk.red('[Error]')} first you should login!`);
|
|
37
|
+
if (!(await this.require_login())) {
|
|
27
38
|
return;
|
|
28
39
|
}
|
|
40
|
+
const selected_service = await this.select_service(flags.service, { 'not_status': 'pending', 'has_custom_plan': 'true' }, 'Resize Service');
|
|
29
41
|
if (!selected_service) {
|
|
30
|
-
|
|
31
|
-
if (all_services) {
|
|
32
|
-
let { service } = await inquirer.prompt({
|
|
33
|
-
type: 'list',
|
|
34
|
-
message: 'Please select a service:',
|
|
35
|
-
name: 'service',
|
|
36
|
-
choices: all_services
|
|
37
|
-
});
|
|
38
|
-
selected_service = service;
|
|
39
|
-
}
|
|
42
|
+
return;
|
|
40
43
|
}
|
|
41
44
|
if (!selected_ram) {
|
|
42
|
-
|
|
43
|
-
type: '
|
|
44
|
-
message: '
|
|
45
|
+
const { ram } = await inquirer.prompt({
|
|
46
|
+
type: 'select',
|
|
47
|
+
message: 'RAM:',
|
|
45
48
|
name: 'ram',
|
|
46
49
|
choices: [
|
|
47
|
-
{ value: "0.5", name: "0.
|
|
48
|
-
{ value: "1", name: "
|
|
49
|
-
{ value: "2", name: "
|
|
50
|
-
{ value: "4", name: "
|
|
51
|
-
{ value: "6", name: "
|
|
52
|
-
{ value: "8", name: "
|
|
50
|
+
{ value: "0.5", name: "0.5 GB" },
|
|
51
|
+
{ value: "1", name: "1 GB" },
|
|
52
|
+
{ value: "2", name: "2 GB" },
|
|
53
|
+
{ value: "4", name: "4 GB" },
|
|
54
|
+
{ value: "6", name: "6 GB" },
|
|
55
|
+
{ value: "8", name: "8 GB" },
|
|
53
56
|
]
|
|
54
57
|
});
|
|
55
58
|
selected_ram = ram;
|
|
56
59
|
}
|
|
57
60
|
if (!selected_cpu) {
|
|
58
|
-
|
|
59
|
-
type: '
|
|
60
|
-
message: '
|
|
61
|
+
const { cpu } = await inquirer.prompt({
|
|
62
|
+
type: 'select',
|
|
63
|
+
message: 'CPU:',
|
|
61
64
|
name: 'cpu',
|
|
62
65
|
choices: [
|
|
63
|
-
{ value: "0.5", name: "0.5
|
|
64
|
-
{ value: "1", name: "1
|
|
65
|
-
{ value: "2", name: "2
|
|
66
|
-
{ value: "3", name: "3
|
|
67
|
-
{ value: "4", name: "4
|
|
66
|
+
{ value: "0.5", name: "0.5 core" },
|
|
67
|
+
{ value: "1", name: "1 core" },
|
|
68
|
+
{ value: "2", name: "2 cores" },
|
|
69
|
+
{ value: "3", name: "3 cores" },
|
|
70
|
+
{ value: "4", name: "4 cores" },
|
|
68
71
|
]
|
|
69
72
|
});
|
|
70
73
|
selected_cpu = cpu;
|
|
71
74
|
}
|
|
72
75
|
if (!selected_disk) {
|
|
73
|
-
|
|
74
|
-
type: '
|
|
75
|
-
message: '
|
|
76
|
+
const { disk } = await inquirer.prompt({
|
|
77
|
+
type: 'select',
|
|
78
|
+
message: 'Disk:',
|
|
76
79
|
name: 'disk',
|
|
77
80
|
choices: [
|
|
78
|
-
{ value: "5", name: "
|
|
79
|
-
{ value: "10", name: "
|
|
80
|
-
{ value: "15", name: "
|
|
81
|
-
{ value: "30", name: "
|
|
82
|
-
{ value: "40", name: "
|
|
83
|
-
{ value: "50", name: "
|
|
81
|
+
{ value: "5", name: "5 GB" },
|
|
82
|
+
{ value: "10", name: "10 GB" },
|
|
83
|
+
{ value: "15", name: "15 GB" },
|
|
84
|
+
{ value: "30", name: "30 GB" },
|
|
85
|
+
{ value: "40", name: "40 GB" },
|
|
86
|
+
{ value: "50", name: "50 GB" },
|
|
84
87
|
]
|
|
85
88
|
});
|
|
86
89
|
selected_disk = disk;
|
|
87
90
|
}
|
|
91
|
+
if (!selected_ram || !selected_cpu || !selected_disk) {
|
|
92
|
+
cli.log(ui.error('RAM, CPU and disk are all required.'));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
88
95
|
let wrong_value = false;
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
const ramNum = Number.parseFloat(selected_ram);
|
|
97
|
+
const cpuNum = Number.parseFloat(selected_cpu);
|
|
98
|
+
const diskNum = Number.parseFloat(selected_disk);
|
|
99
|
+
if (Number.isNaN(ramNum) || ramNum % 0.5 !== 0) {
|
|
100
|
+
cli.log(ui.error(`RAM must be a multiple of 0.5 GB, got ${ui.value(selected_ram)}.`));
|
|
91
101
|
wrong_value = true;
|
|
92
102
|
}
|
|
93
|
-
if (
|
|
94
|
-
cli.log(
|
|
103
|
+
if (Number.isNaN(cpuNum) || cpuNum % 0.5 !== 0) {
|
|
104
|
+
cli.log(ui.error(`CPU must be a multiple of 0.5 cores, got ${ui.value(selected_cpu)}.`));
|
|
95
105
|
wrong_value = true;
|
|
96
106
|
}
|
|
97
|
-
if (
|
|
98
|
-
cli.log(
|
|
107
|
+
if (Number.isNaN(diskNum) || diskNum % 5 !== 0) {
|
|
108
|
+
cli.log(ui.error(`Disk must be a multiple of 5 GB, got ${ui.value(selected_disk)}.`));
|
|
99
109
|
wrong_value = true;
|
|
100
110
|
}
|
|
101
|
-
if (
|
|
102
|
-
|
|
111
|
+
if (wrong_value) {
|
|
112
|
+
cli.log(ui.hint(`Example: ${ui.cmd(`chabok service resize -s ${selected_service} --ram 2 --cpu 1 --disk 10`)}`));
|
|
113
|
+
return;
|
|
103
114
|
}
|
|
115
|
+
await this.send_request(cli, selected_service, selected_ram, selected_cpu, selected_disk);
|
|
104
116
|
}
|
|
105
117
|
async send_request(cli, selected_service, ram, cpu, disk) {
|
|
106
118
|
try {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
+
const { data } = await axios.post(`services/${selected_service}/resize/`, {
|
|
120
|
+
ram,
|
|
121
|
+
cpu,
|
|
122
|
+
disk,
|
|
123
|
+
}, this.axiosConfig);
|
|
124
|
+
if (data.success) {
|
|
125
|
+
cli.log(ui.success(`Service ${ui.value(selected_service)} resized to ${ui.value(`${ram} GB RAM`)}, ${ui.value(`${cpu} CPU`)}, ${ui.value(`${disk} GB disk`)}.`));
|
|
126
|
+
cli.log(ui.hint(`Restart it to apply the new limits: ${ui.cmd(`chabok service restart -s ${selected_service}`)}`));
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
cli.log(ui.error(`Could not resize ${ui.value(selected_service)}. ${data.message || 'Check the resource values and try again.'}`));
|
|
119
130
|
}
|
|
120
131
|
}
|
|
121
|
-
catch (
|
|
122
|
-
|
|
123
|
-
|
|
132
|
+
catch (error) {
|
|
133
|
+
const errorInfo = handleApiError(error, 'Failed to resize service.', {
|
|
134
|
+
endpoint: `services/${selected_service}/resize/`,
|
|
135
|
+
serviceName: selected_service,
|
|
136
|
+
operation: 'Resize Service'
|
|
137
|
+
});
|
|
138
|
+
if (errorInfo.status === 404) {
|
|
139
|
+
cli.log(ui.error(`Service ${ui.value(selected_service)} was not found.`));
|
|
140
|
+
cli.log(ui.hint(`Check the available names with ${ui.cmd('chabok service list')}`));
|
|
141
|
+
}
|
|
142
|
+
else if (errorInfo.status === 400 || errorInfo.status === 422) {
|
|
143
|
+
cli.log(ui.error(errorInfo.message));
|
|
144
|
+
cli.log(ui.hint('RAM and CPU go in steps of 0.5; disk goes in steps of 5'));
|
|
124
145
|
}
|
|
125
146
|
else {
|
|
126
|
-
|
|
147
|
+
cli.log(ui.error(errorInfo.message));
|
|
127
148
|
}
|
|
149
|
+
logErrorDetails(errorInfo, cli);
|
|
128
150
|
}
|
|
129
151
|
}
|
|
130
152
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import Command from "../../base.js";
|
|
2
2
|
export default class ServiceRestart extends Command {
|
|
3
3
|
static description: string;
|
|
4
|
+
static examples: {
|
|
5
|
+
description: string;
|
|
6
|
+
command: string;
|
|
7
|
+
}[];
|
|
4
8
|
static flags: {
|
|
5
|
-
service: import("@oclif/core/
|
|
6
|
-
help: import("@oclif/core/
|
|
9
|
+
service: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
help: import("@oclif/core/interfaces").BooleanFlag<void>;
|
|
7
11
|
};
|
|
8
12
|
run(): Promise<void>;
|
|
9
|
-
send_request(cli:
|
|
13
|
+
send_request(cli: Command, selected_service: string): Promise<void>;
|
|
10
14
|
}
|