@topgroup/diginext
Version:
A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.
172 lines (171 loc) • 9.13 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const log_1 = require("diginext-utils/dist/xconsole/log");
const app_config_1 = require("../../app.config");
const config_1 = require("../../config/config");
const k8s_1 = __importDefault(require("../k8s"));
const kube_config_1 = require("../k8s/kube-config");
const DockerRegistry = {
connectDockerToRegistry: async (creds, options) => {
const { DB } = await Promise.resolve().then(() => __importStar(require("../../modules/api/DB")));
const { execaCommand, execaSync } = await Promise.resolve().then(() => __importStar(require("execa")));
const { workspaceId, registry: registrySlug } = options;
const { server = "https://index.docker.io/v2/", username, password, email } = creds;
if (!password)
throw new Error(`Permissions denied.`);
try {
let connectRes;
if (app_config_1.Config.BUILDER === "docker") {
// connect DOCKER ENGINE to DOCKER REGISTRY
connectRes = await execaCommand(`docker login -u ${username} -p ${password}`);
if (options.isDebugging)
(0, log_1.log)(`[DOCKER] connectDockerRegistry >`, { connectRes });
}
else {
// connect PODMAN to DOCKER REGISTRY
connectRes = await execaCommand(`podman login docker.io -u ${username} -p ${password}`);
if (options.isDebugging)
(0, log_1.log)(`[PODMAN] connectDockerRegistry >`, { connectRes });
}
}
catch (e) {
// NOTE: DO NOT EXPOSE PASSWORD IN THIS LOG DUE TO SECURITY RISK !!!
console.log(`[${app_config_1.Config.BUILDER.toUpperCase()}] connectDockerToRegistry() > error :>>`, (e.message || "unknown").replace(new RegExp(password, "gi"), "***"));
if (!e.message.includes("The specified item already exists in the keychain"))
throw new Error(`[${app_config_1.Config.BUILDER.toUpperCase()}] Unable to connect to Docker Registry (${registrySlug}): Authentication failure.`);
}
const existingRegistry = await DB.findOne("registry", { slug: registrySlug }, { subpath: "/all", ignorable: true });
if (options.isDebugging)
(0, log_1.log)(`[DOCKER] connectDockerRegistry >`, { existingRegistry });
const workspace = await DB.findOne("workspace", { _id: workspaceId || existingRegistry.workspace });
if (!workspace)
throw new Error(`[DOCKER] Workspace not found (${workspaceId}).`);
if (existingRegistry)
return existingRegistry;
// IF NOT EXISTED -> Save this container registry to database!
const imageBaseURL = `${server}/${workspace.slug}`;
const newRegistry = await DB.create("registry", {
name: "Docker Registry",
provider: "dockerhub",
imageBaseURL,
host: server,
username,
password,
email,
workspace: workspaceId,
});
if (options.isDebugging)
(0, log_1.log)(`[DOCKER] Added new container registry: "${newRegistry.name}" (${newRegistry.slug}).`);
return newRegistry;
},
createImagePullSecret: async (options) => {
const { DB } = await Promise.resolve().then(() => __importStar(require("../../modules/api/DB")));
const { execa, execaCommand, execaSync } = await Promise.resolve().then(() => __importStar(require("execa")));
const { registrySlug, namespace = "default", clusterSlug } = options;
if (!clusterSlug)
throw new Error(`Cluster's short name is required.`);
// Get "context" by "cluster" -> to create "imagePullSecrets" of "registry" in cluster's namespace
const cluster = await DB.findOne("cluster", { slug: clusterSlug }, { populate: ["owner", "workspace"], subpath: "/all" });
if (!cluster)
throw new Error(`Can't create "imagePullSecrets" in "${namespace}" namespace of "${clusterSlug}" cluster.`);
// authenticate cluster & switch to that cluster's context
try {
const { owner, workspace } = cluster;
await k8s_1.default.authCluster(cluster, { ownership: { owner: owner, workspace: workspace } });
}
catch (e) {
throw new Error(e.message);
}
const { name: context } = await (0, kube_config_1.getKubeContextByCluster)(cluster);
// get Container Registry data:
const registry = await DB.findOne("registry", { slug: registrySlug }, { subpath: "/all" });
if (!registry) {
throw new Error(`Container Registry (${registrySlug}) not found. Please contact your admin or create a new one.`);
}
const { dockerServer: server = "https://index.docker.io/v2/", dockerUsername: username, dockerEmail: email, dockerPassword: password, } = registry;
if (!password)
throw new Error(`Permissions denied.`);
const secretName = `${registry.slug}-docker-registry-key`;
let secretValue;
// check if namespace is existed
const isNsExisted = await k8s_1.default.isNamespaceExisted(namespace, { context });
if (!isNsExisted) {
// create new namespace?
const ns = await k8s_1.default.createNamespace(namespace, { context });
// still can't create namespace -> throw error!
if (!ns)
throw new Error(`Namespace "${namespace}" is not existed on this cluster ("${clusterSlug}").`);
}
// check if the secret is existed within the namespace, try to delete it!
const isSecretExisted = await k8s_1.default.isSecretExisted(secretName, namespace, { context });
if (isSecretExisted)
await k8s_1.default.deleteSecret(secretName, namespace, { context });
// Create new "imagePullSecret":
// kubectl create secret docker-registry regcred --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>
const createSecretOptions = [`--docker-server=${server}`, `--docker-username=${username}`, `--docker-password=${password}`];
if (email)
createSecretOptions.push(`--docker-email=${email}`);
if (context)
createSecretOptions.push(`--context=${context}`);
// create new image pulling secret (in namespace & in database)
try {
const { stdout: newImagePullingSecret } = await execa(`kubectl`, [
"-n",
namespace,
`create`,
`secret`,
`docker-registry`,
secretName,
...createSecretOptions,
"-o",
"json",
]);
secretValue = JSON.parse(newImagePullingSecret).data[".dockerconfigjson"];
// log({ secretValue });
// save this secret to database:
let updateData = {
imagePullSecret: {
name: secretName,
value: secretValue,
},
};
const updatedRegistries = await DB.update("registry", { slug: registrySlug }, updateData);
const updatedRegistry = updatedRegistries[0];
// save registry to local config:
if (!app_config_1.isServerMode)
(0, config_1.saveCliConfig)({ currentRegistry: updatedRegistry });
(0, log_1.logSuccess)(`[DOCKER] ✓ Successfully assign "imagePullSecret" data (${secretName}) to "${namespace}" namespace of "${clusterSlug}" cluster.`);
return updatedRegistry.imagePullSecret;
}
catch (e) {
throw new Error(`[DOCKER] Cannot create image pull secret: ${e}`.replace(password, "***"));
}
},
};
exports.default = DockerRegistry;