UNPKG

@topgroup/diginext

Version:

A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.

172 lines (171 loc) 9.13 kB
"use strict"; 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;