@quantum-hub/qhubctl 2.2.2-next.1 → 2.2.3-next.1
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 +4 -2
- package/dist/commands/compress.d.ts +1 -1
- package/dist/commands/compress.js +15 -15
- package/dist/commands/datapool-upload.d.ts +1 -1
- package/dist/commands/datapool-upload.js +35 -35
- package/dist/commands/get-context.d.ts +1 -1
- package/dist/commands/get-context.js +5 -5
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +33 -29
- package/dist/commands/list-contexts.d.ts +1 -1
- package/dist/commands/list-contexts.js +21 -13
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.js +16 -16
- package/dist/commands/logout.d.ts +1 -1
- package/dist/commands/logout.js +10 -10
- package/dist/commands/openapi.d.ts +1 -1
- package/dist/commands/openapi.js +112 -94
- package/dist/commands/run.d.ts +3 -3
- package/dist/commands/run.js +37 -34
- package/dist/commands/serve.d.ts +1 -1
- package/dist/commands/serve.js +30 -19
- package/dist/commands/services-build-logs.d.ts +2 -2
- package/dist/commands/services-build-logs.js +26 -26
- package/dist/commands/services-build-status.d.ts +1 -1
- package/dist/commands/services-build-status.js +21 -21
- package/dist/commands/services-list.d.ts +1 -1
- package/dist/commands/services-list.js +20 -17
- package/dist/commands/set-context.d.ts +1 -1
- package/dist/commands/set-context.js +18 -16
- package/dist/commands/up.d.ts +1 -1
- package/dist/commands/up.js +50 -48
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/command.js +2 -2
- package/dist/lib/config-dir.js +3 -3
- package/dist/lib/debug.js +1 -1
- package/dist/lib/entrypoint-resolver.js +15 -15
- package/dist/lib/error.js +4 -4
- package/dist/lib/fetch.js +3 -1
- package/dist/lib/init-user-input.d.ts +1 -1
- package/dist/lib/init-user-input.js +28 -26
- package/dist/lib/output.d.ts +2 -2
- package/dist/lib/output.js +3 -3
- package/dist/lib/random-name.js +147 -147
- package/dist/lib/random-string.js +2 -2
- package/dist/lib/repository.js +5 -5
- package/dist/lib/stream-to-blob.d.ts +1 -1
- package/dist/lib/stream-to-blob.js +5 -5
- package/dist/lib/up/get-description.js +8 -8
- package/dist/lib/up/ignore.js +8 -8
- package/dist/lib/up/qhubignore-help.js +10 -10
- package/dist/lib/up/required-files.js +17 -12
- package/dist/lib/up/source.d.ts +2 -2
- package/dist/lib/up/source.js +7 -7
- package/dist/lib/up/zip.js +8 -8
- package/dist/main.js +3 -3
- package/dist/model/command.d.ts +2 -2
- package/dist/model/command.js +9 -9
- package/dist/model/managed-service-config.d.ts +1 -1
- package/dist/model/user-config.js +1 -1
- package/dist/program.d.ts +1 -1
- package/dist/program.js +24 -24
- package/dist/service/auth-service.d.ts +3 -3
- package/dist/service/auth-service.js +11 -9
- package/dist/service/command-service.d.ts +1 -1
- package/dist/service/quantum-hub-service.d.ts +3 -3
- package/dist/service/quantum-hub-service.js +34 -20
- package/dist/service/service-config-service.d.ts +1 -1
- package/dist/service/service-config-service.js +8 -8
- package/dist/service/user-config-service.d.ts +1 -1
- package/dist/service/user-config-service.js +7 -7
- package/dist/service/user-service.d.ts +2 -2
- package/dist/service/user-service.js +4 -4
- package/package.json +9 -3
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
3
|
function getDescriptionPath(workingDirectory = process.cwd()) {
|
|
4
|
-
const configPath = path.join(workingDirectory,
|
|
4
|
+
const configPath = path.join(workingDirectory, "qhub.json");
|
|
5
5
|
if (fs.existsSync(configPath)) {
|
|
6
|
-
const config = JSON.parse(fs.readFileSync(configPath,
|
|
6
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
7
7
|
if (config.descriptionFile) {
|
|
8
8
|
return path.join(workingDirectory, config.descriptionFile);
|
|
9
9
|
}
|
|
10
|
-
return
|
|
10
|
+
return "";
|
|
11
11
|
}
|
|
12
|
-
throw new Error(
|
|
12
|
+
throw new Error("qhub.json file not found");
|
|
13
13
|
}
|
|
14
14
|
export async function getDescriptionText(workingDirectory = process.cwd()) {
|
|
15
15
|
const descriptionPath = getDescriptionPath(workingDirectory);
|
|
16
16
|
if (descriptionPath) {
|
|
17
17
|
if (fs.existsSync(descriptionPath)) {
|
|
18
|
-
return fs.readFileSync(descriptionPath,
|
|
18
|
+
return fs.readFileSync(descriptionPath, "utf8");
|
|
19
19
|
}
|
|
20
20
|
throw new Error('Provided "descriptionFile" was not found');
|
|
21
21
|
}
|
|
22
|
-
return
|
|
22
|
+
return "";
|
|
23
23
|
}
|
package/dist/lib/up/ignore.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import ignore from
|
|
2
|
-
import fs from
|
|
3
|
-
import path from
|
|
4
|
-
import { promisify } from
|
|
1
|
+
import ignore from "ignore";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
5
|
const readFile = promisify(fs.readFile);
|
|
6
6
|
// Always excluded from the upload archive. Added before user patterns so a
|
|
7
7
|
// user can re-include any of them with a negation (e.g. `!node_modules`).
|
|
8
|
-
const DEFAULT_IGNORES = [
|
|
8
|
+
const DEFAULT_IGNORES = [".git", "node_modules", ".venv", "__pycache__", "service.zip"];
|
|
9
9
|
export async function createIgnoreFileChecker(filePath = process.cwd()) {
|
|
10
10
|
const ig = ignore().add(DEFAULT_IGNORES);
|
|
11
|
-
const ignoreFilePath = path.join(filePath,
|
|
11
|
+
const ignoreFilePath = path.join(filePath, ".qhubignore");
|
|
12
12
|
if (fs.existsSync(ignoreFilePath)) {
|
|
13
|
-
const ignoreFileContents = await readFile(ignoreFilePath,
|
|
14
|
-
ig.add(ignoreFileContents.split(
|
|
13
|
+
const ignoreFileContents = await readFile(ignoreFilePath, "utf8");
|
|
14
|
+
ig.add(ignoreFileContents.split("\n"));
|
|
15
15
|
}
|
|
16
16
|
return (fullPath) => ig.ignores(fullPath);
|
|
17
17
|
}
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export const QHUBIGNORE_HELP = [
|
|
8
8
|
"Use a '.qhubignore' file (gitignore syntax) to exclude files and directories from the ZIP file.",
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
"",
|
|
10
|
+
"`.git`, `node_modules`, `.venv`, `__pycache__`, and `service.zip` are always excluded.",
|
|
11
11
|
"Because `.qhubignore` uses gitignore syntax, re-including a directory's contents requires both the directory and its contents — for example, to ship only `src` and the `Dockerfile`:",
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
].join(
|
|
12
|
+
"",
|
|
13
|
+
"```",
|
|
14
|
+
"*",
|
|
15
|
+
"!src",
|
|
16
|
+
"!src/**",
|
|
17
|
+
"!Dockerfile",
|
|
18
|
+
"```",
|
|
19
|
+
].join("\n");
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
3
|
-
import { Runtime } from
|
|
4
|
-
import { readServiceConfig } from
|
|
5
|
-
import { createIgnoreFileChecker } from
|
|
6
|
-
import { warn } from
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { Runtime } from "../../model/managed-service-config.js";
|
|
4
|
+
import { readServiceConfig } from "../../service/service-config-service.js";
|
|
5
|
+
import { createIgnoreFileChecker } from "./ignore.js";
|
|
6
|
+
import { warn } from "../output.js";
|
|
7
7
|
const REQUIRED_FILES = {
|
|
8
|
-
[Runtime.DOCKER]: [
|
|
9
|
-
[Runtime.PYTHON_TEMPLATE]: [
|
|
8
|
+
[Runtime.DOCKER]: ["Dockerfile"],
|
|
9
|
+
[Runtime.PYTHON_TEMPLATE]: ["requirements.txt", "src/program.py"],
|
|
10
10
|
};
|
|
11
11
|
export async function evaluateRequiredFiles(workingDirectory) {
|
|
12
|
-
const result = {
|
|
13
|
-
|
|
12
|
+
const result = {
|
|
13
|
+
skipped: false,
|
|
14
|
+
runtimeMissing: false,
|
|
15
|
+
missing: [],
|
|
16
|
+
excluded: [],
|
|
17
|
+
};
|
|
18
|
+
if (!fs.existsSync(path.join(workingDirectory, "qhub.json"))) {
|
|
14
19
|
result.skipped = true;
|
|
15
20
|
return result;
|
|
16
21
|
}
|
|
@@ -39,10 +44,10 @@ export async function enforceRequiredFiles(workingDirectory) {
|
|
|
39
44
|
return;
|
|
40
45
|
}
|
|
41
46
|
if (missing.length > 0) {
|
|
42
|
-
warn(`Required file(s) missing for the configured runtime: ${missing.join(
|
|
47
|
+
warn(`Required file(s) missing for the configured runtime: ${missing.join(", ")}`);
|
|
43
48
|
}
|
|
44
49
|
if (excluded.length > 0) {
|
|
45
|
-
throw new Error(`Required file(s) are present but excluded by .qhubignore: ${excluded.join(
|
|
50
|
+
throw new Error(`Required file(s) are present but excluded by .qhubignore: ${excluded.join(", ")}. ` +
|
|
46
51
|
`Re-include them with a negation (e.g. "!Dockerfile").`);
|
|
47
52
|
}
|
|
48
53
|
}
|
package/dist/lib/up/source.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { HubPlatform } from
|
|
2
|
-
import ManagedServiceConfig from
|
|
1
|
+
import { HubPlatform } from "@quantum-hub/qhub-api/platform";
|
|
2
|
+
import ManagedServiceConfig from "../../model/managed-service-config.js";
|
|
3
3
|
export interface RegistryCredentials {
|
|
4
4
|
username?: string;
|
|
5
5
|
password?: string;
|
package/dist/lib/up/source.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
const DEFAULT_TAG =
|
|
1
|
+
const DEFAULT_TAG = "latest";
|
|
2
2
|
/**
|
|
3
3
|
* Splits an image reference (`registry/repo:tag`) into its image and tag.
|
|
4
4
|
* The tag defaults to `latest`. A colon belonging to a registry `host:port`
|
|
5
5
|
* (i.e. before the last path segment) is not treated as a tag separator.
|
|
6
6
|
*/
|
|
7
7
|
export function parseImageRef(ref) {
|
|
8
|
-
const lastSlash = ref.lastIndexOf(
|
|
9
|
-
const lastColon = ref.lastIndexOf(
|
|
8
|
+
const lastSlash = ref.lastIndexOf("/");
|
|
9
|
+
const lastColon = ref.lastIndexOf(":");
|
|
10
10
|
if (lastColon > lastSlash) {
|
|
11
11
|
return { image: ref.slice(0, lastColon), tag: ref.slice(lastColon + 1) || DEFAULT_TAG };
|
|
12
12
|
}
|
|
@@ -32,7 +32,7 @@ export function resolveRegistryCredentials(flags, env) {
|
|
|
32
32
|
* `source.type: "registry"`, or when an `--image` override is supplied.
|
|
33
33
|
*/
|
|
34
34
|
export function isRegistrySource(config, imageOverride) {
|
|
35
|
-
return Boolean(imageOverride) || config.source?.type ===
|
|
35
|
+
return Boolean(imageOverride) || config.source?.type === "registry";
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
38
|
* Builds the platform ServiceSource for an `up` deploy.
|
|
@@ -42,13 +42,13 @@ export function isRegistrySource(config, imageOverride) {
|
|
|
42
42
|
*/
|
|
43
43
|
export function buildServiceSource(config, imageOverride, credentials) {
|
|
44
44
|
if (!isRegistrySource(config, imageOverride)) {
|
|
45
|
-
return { type:
|
|
45
|
+
return { type: "file" };
|
|
46
46
|
}
|
|
47
47
|
const { image, tag } = resolveImageRef(config, imageOverride);
|
|
48
48
|
if (!image) {
|
|
49
49
|
throw new Error('A registry source requires an image. Set "source.image" in qhub.json or pass --image.');
|
|
50
50
|
}
|
|
51
|
-
const source = { type:
|
|
51
|
+
const source = { type: "registry", image, tag };
|
|
52
52
|
if (credentials?.username)
|
|
53
53
|
source.username = credentials.username;
|
|
54
54
|
if (credentials?.password)
|
|
@@ -59,5 +59,5 @@ function resolveImageRef(config, imageOverride) {
|
|
|
59
59
|
if (imageOverride) {
|
|
60
60
|
return parseImageRef(imageOverride);
|
|
61
61
|
}
|
|
62
|
-
return { image: config.source?.image ??
|
|
62
|
+
return { image: config.source?.image ?? "", tag: config.source?.tag ?? DEFAULT_TAG };
|
|
63
63
|
}
|
package/dist/lib/up/zip.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import AdmZip from
|
|
2
|
-
import fs from
|
|
3
|
-
import { tmpdir } from
|
|
4
|
-
import path from
|
|
5
|
-
import { streamToBlob } from
|
|
6
|
-
import { createIgnoreFileChecker } from
|
|
7
|
-
export async function zipProjectFolder(workingDirectory = process.cwd(), targetDirectory = tmpdir(), targetFilename =
|
|
8
|
-
const targetFilePath = path.join(targetDirectory,
|
|
1
|
+
import AdmZip from "adm-zip";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { streamToBlob } from "../stream-to-blob.js";
|
|
6
|
+
import { createIgnoreFileChecker } from "./ignore.js";
|
|
7
|
+
export async function zipProjectFolder(workingDirectory = process.cwd(), targetDirectory = tmpdir(), targetFilename = "user_code.zip") {
|
|
8
|
+
const targetFilePath = path.join(targetDirectory, "/", targetFilename);
|
|
9
9
|
if (fs.existsSync(targetFilePath)) {
|
|
10
10
|
fs.unlinkSync(targetFilePath);
|
|
11
11
|
}
|
package/dist/main.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Suppress Node.js experimental/deprecation warnings
|
|
3
|
-
process.removeAllListeners(
|
|
3
|
+
process.removeAllListeners("warning");
|
|
4
4
|
// Disable SSL/TLS certificate verification
|
|
5
5
|
// (required for some on-premise Quantum Hub deployments)
|
|
6
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED =
|
|
7
|
-
import { program } from
|
|
6
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
7
|
+
import { program } from "./program.js";
|
|
8
8
|
await program.parseAsync(process.argv);
|
package/dist/model/command.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import UserConfig from
|
|
2
|
-
export { configDir } from
|
|
1
|
+
import UserConfig from "./user-config.js";
|
|
2
|
+
export { configDir } from "../lib/config-dir.js";
|
|
3
3
|
export declare function getUserConfig(): UserConfig;
|
|
4
4
|
export declare function getContextDisplayString(userConfig: UserConfig): string;
|
|
5
5
|
export declare function showCustomBasePathWarning(): void;
|
package/dist/model/command.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { configDir } from
|
|
2
|
-
import { stdout, warn } from
|
|
3
|
-
import AuthService from
|
|
4
|
-
import { readUserConfig, writeUserConfig } from
|
|
5
|
-
export { configDir } from
|
|
1
|
+
import { configDir } from "../lib/config-dir.js";
|
|
2
|
+
import { stdout, warn } from "../lib/output.js";
|
|
3
|
+
import AuthService from "../service/auth-service.js";
|
|
4
|
+
import { readUserConfig, writeUserConfig } from "../service/user-config-service.js";
|
|
5
|
+
export { configDir } from "../lib/config-dir.js";
|
|
6
6
|
export function getUserConfig() {
|
|
7
7
|
return readUserConfig(configDir);
|
|
8
8
|
}
|
|
9
9
|
export function getContextDisplayString(userConfig) {
|
|
10
10
|
if (userConfig?.context) {
|
|
11
|
-
const type = userConfig.context.isOrganization ?
|
|
11
|
+
const type = userConfig.context.isOrganization ? "Organization" : "Personal";
|
|
12
12
|
return `${userConfig.context.displayName} (${type})`;
|
|
13
13
|
}
|
|
14
14
|
return 'No context set. Use "qhubctl set-context" to set a context.';
|
|
15
15
|
}
|
|
16
16
|
export function showCustomBasePathWarning() {
|
|
17
|
-
warn(
|
|
17
|
+
warn("Using custom base path. This is intended for internal development use only.");
|
|
18
18
|
stdout();
|
|
19
19
|
}
|
|
20
20
|
export function showBasePathRevertNotice() {
|
|
21
|
-
warn(
|
|
21
|
+
warn("Custom base path removed. Using the default base path.");
|
|
22
22
|
stdout();
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
@@ -49,7 +49,7 @@ export async function requireAuth(opts = {}) {
|
|
|
49
49
|
throw new Error('Invalid credentials provided. Use the "login" command to log in.');
|
|
50
50
|
}
|
|
51
51
|
if (printContext) {
|
|
52
|
-
stdout(
|
|
52
|
+
stdout("Current context: " + getContextDisplayString(userConfig));
|
|
53
53
|
}
|
|
54
54
|
return userConfig;
|
|
55
55
|
}
|
|
@@ -2,7 +2,7 @@ export var AuthType;
|
|
|
2
2
|
(function (AuthType) {
|
|
3
3
|
AuthType["API_KEY"] = "API_KEY";
|
|
4
4
|
})(AuthType || (AuthType = {}));
|
|
5
|
-
export const defaultBasePath =
|
|
5
|
+
export const defaultBasePath = "https://api.hub.kipu-quantum.com";
|
|
6
6
|
/**
|
|
7
7
|
* Resolves the endpoint to use for a login attempt.
|
|
8
8
|
*
|
package/dist/program.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Command } from
|
|
1
|
+
import { Command } from "commander";
|
|
2
2
|
export declare const program: Command;
|
package/dist/program.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { Command } from
|
|
2
|
-
import { createRequire } from
|
|
3
|
-
import updateNotifier from
|
|
4
|
-
import { compressCommand } from
|
|
5
|
-
import { datapoolUploadCommand } from
|
|
6
|
-
import { getContextCommand } from
|
|
7
|
-
import { initCommand } from
|
|
8
|
-
import { listContextsCommand } from
|
|
9
|
-
import { loginCommand } from
|
|
10
|
-
import { logoutCommand } from
|
|
11
|
-
import { openapiCommand } from
|
|
12
|
-
import { runCommand } from
|
|
13
|
-
import { serveCommand } from
|
|
14
|
-
import { servicesBuildLogsCommand } from
|
|
15
|
-
import { servicesBuildStatusCommand } from
|
|
16
|
-
import { servicesListCommand } from
|
|
17
|
-
import { setContextCommand } from
|
|
18
|
-
import { upCommand } from
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import updateNotifier from "update-notifier";
|
|
4
|
+
import { compressCommand } from "./commands/compress.js";
|
|
5
|
+
import { datapoolUploadCommand } from "./commands/datapool-upload.js";
|
|
6
|
+
import { getContextCommand } from "./commands/get-context.js";
|
|
7
|
+
import { initCommand } from "./commands/init.js";
|
|
8
|
+
import { listContextsCommand } from "./commands/list-contexts.js";
|
|
9
|
+
import { loginCommand } from "./commands/login.js";
|
|
10
|
+
import { logoutCommand } from "./commands/logout.js";
|
|
11
|
+
import { openapiCommand } from "./commands/openapi.js";
|
|
12
|
+
import { runCommand } from "./commands/run.js";
|
|
13
|
+
import { serveCommand } from "./commands/serve.js";
|
|
14
|
+
import { servicesBuildLogsCommand } from "./commands/services-build-logs.js";
|
|
15
|
+
import { servicesBuildStatusCommand } from "./commands/services-build-status.js";
|
|
16
|
+
import { servicesListCommand } from "./commands/services-list.js";
|
|
17
|
+
import { setContextCommand } from "./commands/set-context.js";
|
|
18
|
+
import { upCommand } from "./commands/up.js";
|
|
19
19
|
const require = createRequire(import.meta.url);
|
|
20
|
-
const pkg = require(
|
|
20
|
+
const pkg = require("../package.json");
|
|
21
21
|
// Check for updates in the background (non-blocking).
|
|
22
22
|
updateNotifier({ pkg, updateCheckInterval: 24 * 60 * 60 * 1000 }).notify();
|
|
23
23
|
export const program = new Command()
|
|
24
|
-
.name(
|
|
24
|
+
.name("qhubctl")
|
|
25
25
|
.description(pkg.description)
|
|
26
|
-
.version(pkg.version,
|
|
26
|
+
.version(pkg.version, "-v, --version");
|
|
27
27
|
// Top-level commands
|
|
28
28
|
program.addCommand(compressCommand);
|
|
29
29
|
program.addCommand(getContextCommand);
|
|
@@ -35,7 +35,7 @@ program.addCommand(openapiCommand);
|
|
|
35
35
|
program.addCommand(runCommand);
|
|
36
36
|
program.addCommand(serveCommand);
|
|
37
37
|
// Nested: services <subcommand>
|
|
38
|
-
const servicesCommand = new Command(
|
|
38
|
+
const servicesCommand = new Command("services").description("Manage services");
|
|
39
39
|
servicesCommand.addCommand(servicesListCommand);
|
|
40
40
|
servicesCommand.addCommand(servicesBuildStatusCommand);
|
|
41
41
|
servicesCommand.addCommand(servicesBuildLogsCommand);
|
|
@@ -43,11 +43,11 @@ program.addCommand(servicesCommand);
|
|
|
43
43
|
program.addCommand(setContextCommand);
|
|
44
44
|
program.addCommand(upCommand);
|
|
45
45
|
// Nested: datapool <subcommand>
|
|
46
|
-
const datapoolCommand = new Command(
|
|
46
|
+
const datapoolCommand = new Command("datapool").description("Manage data pools");
|
|
47
47
|
datapoolCommand.addCommand(datapoolUploadCommand);
|
|
48
48
|
program.addCommand(datapoolCommand);
|
|
49
49
|
// Surface a clear error for unknown commands instead of silently doing nothing
|
|
50
|
-
program.on(
|
|
50
|
+
program.on("command:*", (operands) => {
|
|
51
51
|
process.stderr.write(`\n Error: Unknown command '${operands[0]}'\n\n`);
|
|
52
52
|
process.stderr.write(` Run 'qhubctl help' to see available commands.\n\n`);
|
|
53
53
|
process.exit(1);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { HubUser } from
|
|
2
|
-
import UserConfig from
|
|
3
|
-
import UserService from
|
|
1
|
+
import { HubUser } from "@quantum-hub/qhub-api/user";
|
|
2
|
+
import UserConfig from "../model/user-config.js";
|
|
3
|
+
import UserService from "./user-service.js";
|
|
4
4
|
export default class AuthService {
|
|
5
5
|
userConfig: UserConfig;
|
|
6
6
|
userService: UserService;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { fetchOrThrow, PlatformError } from
|
|
2
|
-
import { defaultBasePath } from
|
|
3
|
-
import UserService from
|
|
1
|
+
import { fetchOrThrow, PlatformError } from "../lib/fetch.js";
|
|
2
|
+
import { defaultBasePath } from "../model/user-config.js";
|
|
3
|
+
import UserService from "./user-service.js";
|
|
4
4
|
export default class AuthService {
|
|
5
5
|
userConfig;
|
|
6
6
|
userService;
|
|
@@ -10,23 +10,25 @@ export default class AuthService {
|
|
|
10
10
|
}
|
|
11
11
|
async authenticate(apiKey) {
|
|
12
12
|
try {
|
|
13
|
-
const basePath = (this.userConfig.endpoint?.basePath || defaultBasePath) +
|
|
14
|
-
await fetchOrThrow(basePath +
|
|
15
|
-
headers: {
|
|
16
|
-
method:
|
|
13
|
+
const basePath = (this.userConfig.endpoint?.basePath || defaultBasePath) + "/qc-catalog";
|
|
14
|
+
await fetchOrThrow(basePath + "/authorize", {
|
|
15
|
+
headers: { "X-Auth-Token": apiKey },
|
|
16
|
+
method: "POST",
|
|
17
17
|
});
|
|
18
18
|
return await this.userService.getCurrentUser(apiKey);
|
|
19
19
|
}
|
|
20
20
|
catch (error) {
|
|
21
21
|
if (error instanceof PlatformError) {
|
|
22
22
|
if (error.response.status === 401) {
|
|
23
|
-
throw new Error(
|
|
23
|
+
throw new Error("Invalid API key", { cause: error });
|
|
24
24
|
}
|
|
25
25
|
const errorMessage = await error.getErrorMessage();
|
|
26
26
|
throw new Error(errorMessage, { cause: error });
|
|
27
27
|
}
|
|
28
28
|
console.error(JSON.stringify(error));
|
|
29
|
-
throw new Error(
|
|
29
|
+
throw new Error("Internal error occurred, please contact your Quantum Hub administrator", {
|
|
30
|
+
cause: error,
|
|
31
|
+
});
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HubPlatform, HubPlatformClient } from "@quantum-hub/qhub-api/platform";
|
|
2
|
-
import ManagedServiceConfig from
|
|
3
|
-
import UserConfig from
|
|
4
|
-
import { CommandService } from
|
|
2
|
+
import ManagedServiceConfig from "../model/managed-service-config.js";
|
|
3
|
+
import UserConfig from "../model/user-config.js";
|
|
4
|
+
import { CommandService } from "./command-service.js";
|
|
5
5
|
export default class QuantumHubService extends CommandService {
|
|
6
6
|
apiClient: HubPlatformClient;
|
|
7
7
|
constructor(userConfig: UserConfig);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { HubPlatform, HubPlatformClient } from "@quantum-hub/qhub-api/platform";
|
|
2
|
-
import { handleError } from
|
|
3
|
-
import { defaultBasePath } from
|
|
4
|
-
import { CommandService } from
|
|
2
|
+
import { handleError } from "../lib/error.js";
|
|
3
|
+
import { defaultBasePath } from "../model/user-config.js";
|
|
4
|
+
import { CommandService } from "./command-service.js";
|
|
5
5
|
export default class QuantumHubService extends CommandService {
|
|
6
6
|
apiClient;
|
|
7
7
|
constructor(userConfig) {
|
|
8
8
|
super(userConfig);
|
|
9
|
-
const basePath = (userConfig.endpoint?.basePath || defaultBasePath) +
|
|
9
|
+
const basePath = (userConfig.endpoint?.basePath || defaultBasePath) + "/qc-catalog";
|
|
10
10
|
const apiKey = userConfig.auth?.value;
|
|
11
11
|
const organizationId = userConfig.context?.isOrganization ? userConfig.context.id : undefined;
|
|
12
12
|
this.apiClient = new HubPlatformClient({
|
|
@@ -27,10 +27,10 @@ export default class QuantumHubService extends CommandService {
|
|
|
27
27
|
async createService(serviceConfig, source, sourceCode) {
|
|
28
28
|
const milliCpus = (serviceConfig.resources?.cpu || 1) * 1000;
|
|
29
29
|
const memoryInMegabytes = (serviceConfig.resources?.memory || 2) * 1024;
|
|
30
|
-
const gpuAccelerator = serviceConfig.resources?.gpu?.type ||
|
|
30
|
+
const gpuAccelerator = serviceConfig.resources?.gpu?.type || "NONE";
|
|
31
31
|
const gpuCount = serviceConfig.resources?.gpu?.count || 0;
|
|
32
32
|
// A registry source references a pre-built image, so it always runs the DOCKER runtime.
|
|
33
|
-
const runtime = source.type ===
|
|
33
|
+
const runtime = source.type === "registry" ? "DOCKER" : serviceConfig.runtime;
|
|
34
34
|
try {
|
|
35
35
|
const service = await this.apiClient.managedServices.createManagedService({
|
|
36
36
|
name: serviceConfig.name,
|
|
@@ -38,12 +38,12 @@ export default class QuantumHubService extends CommandService {
|
|
|
38
38
|
runtime: runtime,
|
|
39
39
|
},
|
|
40
40
|
resourceConfigurations: [
|
|
41
|
-
{ type:
|
|
42
|
-
{ type:
|
|
41
|
+
{ type: "cpu", amount: milliCpus, unit: "m" },
|
|
42
|
+
{ type: "memory", amount: memoryInMegabytes, unit: "M" },
|
|
43
43
|
{
|
|
44
|
-
type:
|
|
44
|
+
type: "gpu",
|
|
45
45
|
amount: gpuCount,
|
|
46
|
-
accelerator: gpuAccelerator
|
|
46
|
+
accelerator: gpuAccelerator,
|
|
47
47
|
},
|
|
48
48
|
],
|
|
49
49
|
source,
|
|
@@ -119,7 +119,9 @@ export default class QuantumHubService extends CommandService {
|
|
|
119
119
|
}
|
|
120
120
|
async updateDescription(serviceConfig, description) {
|
|
121
121
|
try {
|
|
122
|
-
await this.apiClient.services.updateServiceDescription(serviceConfig.serviceId, {
|
|
122
|
+
await this.apiClient.services.updateServiceDescription(serviceConfig.serviceId, {
|
|
123
|
+
description,
|
|
124
|
+
});
|
|
123
125
|
}
|
|
124
126
|
catch (error) {
|
|
125
127
|
const errorMessage = await handleError(error);
|
|
@@ -128,7 +130,9 @@ export default class QuantumHubService extends CommandService {
|
|
|
128
130
|
}
|
|
129
131
|
async updateOpenapi(serviceConfig, openapi) {
|
|
130
132
|
try {
|
|
131
|
-
await this.apiClient.services.updateServiceOpenApi(serviceConfig.serviceId, {
|
|
133
|
+
await this.apiClient.services.updateServiceOpenApi(serviceConfig.serviceId, {
|
|
134
|
+
file: openapi,
|
|
135
|
+
});
|
|
132
136
|
}
|
|
133
137
|
catch (error) {
|
|
134
138
|
const errorMessage = await handleError(error);
|
|
@@ -148,8 +152,10 @@ export default class QuantumHubService extends CommandService {
|
|
|
148
152
|
*/
|
|
149
153
|
async updateServiceSource(serviceId, source) {
|
|
150
154
|
try {
|
|
151
|
-
if (source.type ===
|
|
152
|
-
await this.apiClient.managedServices.updateManagedServiceRuntimeConfiguration(serviceId, {
|
|
155
|
+
if (source.type === "registry") {
|
|
156
|
+
await this.apiClient.managedServices.updateManagedServiceRuntimeConfiguration(serviceId, {
|
|
157
|
+
runtime: "DOCKER",
|
|
158
|
+
});
|
|
153
159
|
}
|
|
154
160
|
await this.apiClient.managedServices.updateManagedServiceSource(serviceId, source);
|
|
155
161
|
}
|
|
@@ -162,23 +168,29 @@ export default class QuantumHubService extends CommandService {
|
|
|
162
168
|
const serviceId = serviceConfig.serviceId;
|
|
163
169
|
const milliCpus = (serviceConfig.resources?.cpu || 1) * 1000;
|
|
164
170
|
const memoryInMegabytes = (serviceConfig.resources?.memory || 2) * 1024;
|
|
165
|
-
const gpuAccelerator = serviceConfig.resources?.gpu?.type ||
|
|
171
|
+
const gpuAccelerator = serviceConfig.resources?.gpu?.type || "NONE";
|
|
166
172
|
const gpuCount = serviceConfig.resources?.gpu?.count || 0;
|
|
167
173
|
try {
|
|
168
174
|
if (description) {
|
|
169
175
|
await this.apiClient.services.updateServiceDescription(serviceId, { description });
|
|
170
176
|
}
|
|
171
177
|
if (serviceConfig.summary) {
|
|
172
|
-
await this.apiClient.services.updateServiceSummary(serviceId, {
|
|
178
|
+
await this.apiClient.services.updateServiceSummary(serviceId, {
|
|
179
|
+
summary: serviceConfig.summary,
|
|
180
|
+
});
|
|
173
181
|
}
|
|
174
182
|
await this.apiClient.managedServices.updateManagedServiceResourceConfiguration(serviceId, {
|
|
175
|
-
type:
|
|
183
|
+
type: "cpu",
|
|
184
|
+
amount: milliCpus,
|
|
185
|
+
unit: "m",
|
|
176
186
|
});
|
|
177
187
|
await this.apiClient.managedServices.updateManagedServiceResourceConfiguration(serviceId, {
|
|
178
|
-
type:
|
|
188
|
+
type: "memory",
|
|
189
|
+
amount: memoryInMegabytes,
|
|
190
|
+
unit: "M",
|
|
179
191
|
});
|
|
180
192
|
await this.apiClient.managedServices.updateManagedServiceResourceConfiguration(serviceId, {
|
|
181
|
-
type:
|
|
193
|
+
type: "gpu",
|
|
182
194
|
amount: gpuCount,
|
|
183
195
|
accelerator: gpuAccelerator,
|
|
184
196
|
});
|
|
@@ -194,6 +206,8 @@ export default class QuantumHubService extends CommandService {
|
|
|
194
206
|
}
|
|
195
207
|
}
|
|
196
208
|
async uploadSourceCode(serviceId, sourceCode) {
|
|
197
|
-
await this.apiClient.managedServices.uploadManagedServiceSource(serviceId, {
|
|
209
|
+
await this.apiClient.managedServices.uploadManagedServiceSource(serviceId, {
|
|
210
|
+
file: sourceCode,
|
|
211
|
+
});
|
|
198
212
|
}
|
|
199
213
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import ManagedServiceConfig from
|
|
1
|
+
import ManagedServiceConfig from "../model/managed-service-config.js";
|
|
2
2
|
export declare const readServiceConfig: (location: string) => ManagedServiceConfig;
|
|
3
3
|
export declare const writeServiceConfig: (location: string, serviceConfig: ManagedServiceConfig) => ManagedServiceConfig;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import fsExtra from
|
|
1
|
+
import fsExtra from "fs-extra";
|
|
2
2
|
const { createFileSync, readJsonSync, writeJsonSync } = fsExtra;
|
|
3
|
-
import fs from
|
|
4
|
-
import path from
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
5
|
export const readServiceConfig = (location) => {
|
|
6
|
-
const file = path.join(location,
|
|
6
|
+
const file = path.join(location, "qhub.json");
|
|
7
7
|
if (!fs.existsSync(file)) {
|
|
8
|
-
throw new Error(
|
|
8
|
+
throw new Error("No qhub.json file found in current directory");
|
|
9
9
|
}
|
|
10
|
-
return readJsonSync(file, { encoding:
|
|
10
|
+
return readJsonSync(file, { encoding: "utf8" });
|
|
11
11
|
};
|
|
12
12
|
export const writeServiceConfig = (location, serviceConfig) => {
|
|
13
|
-
const file = path.join(location,
|
|
13
|
+
const file = path.join(location, "qhub.json");
|
|
14
14
|
if (!fs.existsSync(file)) {
|
|
15
15
|
createFileSync(file);
|
|
16
16
|
}
|
|
17
|
-
writeJsonSync(file, serviceConfig, { encoding:
|
|
17
|
+
writeJsonSync(file, serviceConfig, { encoding: "utf8", spaces: 2 });
|
|
18
18
|
return readServiceConfig(location);
|
|
19
19
|
};
|