@topgroup/diginext
Version:
A BUILD SERVER & CLI to deploy apps to any Kubernetes clusters.
194 lines (193 loc) • 10.6 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 });
exports.authClusterBySlug = exports.authCluster = exports.switchContextToCluster = exports.switchContext = void 0;
const log_1 = require("diginext-utils/dist/xconsole/log");
const fs_1 = require("fs");
const plugins_1 = require("../../plugins");
const custom_1 = __importDefault(require("../providers/custom"));
const digitalocean_1 = __importDefault(require("../providers/digitalocean"));
const gcloud_1 = __importDefault(require("../providers/gcloud"));
const kube_config_1 = require("./kube-config");
const switchContext = async (context) => {
const result = await (0, plugins_1.execCmd)(`kubectl config use-context ${context}`, `[CLUSTER AUTH] Cannot switch current kube context to "${context}"`);
return typeof result !== "undefined";
};
exports.switchContext = switchContext;
const switchContextToCluster = async (clusterSlug, providerShortName) => {
const { DB } = await Promise.resolve().then(() => __importStar(require("../../modules/api/DB")));
let context;
if (providerShortName) {
const ctx = await (0, kube_config_1.getKubeContextByClusterSlug)(clusterSlug, providerShortName);
context = ctx.name;
}
else {
const cluster = await DB.findOne("cluster", { slug: clusterSlug });
if (!cluster) {
(0, log_1.logError)(`Can't switch to cluster "${clusterSlug}".`);
return;
}
context = cluster.contextName;
if (!context && cluster.providerShortName) {
const ctx = await (0, kube_config_1.getKubeContextByClusterSlug)(clusterSlug, cluster.providerShortName);
context = ctx.name;
}
}
if (!context) {
(0, log_1.logError)(`[CLUSTER AUTH] Cannot switch current kube context to "${clusterSlug}"`);
return;
}
const result = await (0, plugins_1.execCmd)(`kubectl config use-context ${context}`, `[CLUSTER AUTH] Cannot switch current kube context to "${clusterSlug}"`);
return typeof result !== "undefined";
};
exports.switchContextToCluster = switchContextToCluster;
/**
* Authenticate current machine with the K8S cluster by its short name (context-name).
*/
const authCluster = async (cluster, options) => {
const { DB } = await Promise.resolve().then(() => __importStar(require("../../modules/api/DB")));
const { shouldSwitchContextToThisCluster = true, isDebugging } = options;
const { providerShortName, slug: clusterSlug } = cluster;
if (isDebugging)
console.log("[AUTH CLUSTER] cluster :>> ", cluster);
if (!clusterSlug)
throw new Error(`Param "slug" (cluster's slug) is required.`);
if (!providerShortName)
throw new Error(`Param "provider" (Cloud Provider's short name) is required.`);
let filePath;
let context;
switch (providerShortName) {
case "gcloud":
// Only support Google Service Account authentication
const { serviceAccount } = cluster;
if (cluster.isVerified && !serviceAccount)
throw new Error(`Permissions denied, please contact your administrator.`);
if (!serviceAccount)
throw new Error(`This cluster doesn't have any Google Service Account to authenticate.`);
// validate service account file:
const saConfig = JSON.parse(serviceAccount);
if (!saConfig.project_id)
throw new Error(`Invalid Google service account.`);
const projectID = saConfig.project_id;
// start authenticating...
filePath = (0, plugins_1.createTmpFile)(`gsa.json`, serviceAccount);
const gcloudAuth = await gcloud_1.default.authenticate({ filePath });
if (!gcloudAuth)
throw new Error(`[UNKNOWN] Cannot authenticate the Google Cloud provider.`);
// delete temporary service account
(0, fs_1.unlink)(filePath, (err) => err && (0, log_1.logError)(`[CLUSTER AUTH] Remove tmp file:`, err));
// save this cluster to KUBE_CONFIG
if (!cluster.zone)
throw new Error(`ZONE is required for Google Cloud Cluster authentication.`);
await (0, plugins_1.execCmd)(`gcloud container clusters get-credentials ${cluster.shortName} --zone=${cluster.zone} --project=${projectID}`);
// get K8S context
context = await (0, kube_config_1.getKubeContextByCluster)(cluster);
if (context) {
cluster = await DB.updateOne("cluster", { slug: clusterSlug }, { contextName: context.name }, { ownership: options.ownership });
}
else {
throw new Error(`Context of "${clusterSlug}" cluster not found.`);
}
// switch context (if needed)
// if (shouldSwitchContextToThisCluster) await switchContext(context.name);
// mark this cluster verified
cluster = await DB.updateOne("cluster", { slug: clusterSlug }, { isVerified: true }, { ownership: options.ownership });
(0, log_1.logSuccess)(`[CLUSTER MANAGER] ✓ Connected to "${clusterSlug}" cluster.`);
return cluster;
case "digitalocean":
// Only support Digital Ocean API access token authentication
const { apiAccessToken } = cluster;
if (cluster.isVerified && !apiAccessToken)
throw new Error(`Permissions denied, please contact your administrator.`);
if (!apiAccessToken) {
throw new Error(`This cluster doesn't have any Digital Ocean API access token to authenticate.`);
}
const doAuth = await digitalocean_1.default.authenticate({ key: apiAccessToken });
if (!doAuth)
throw new Error(`[UNKNOWN] Cannot authenticate the Digital Ocean provider.`);
// save cluster access info to "kubeconfig"
await (0, plugins_1.execCmd)(`doctl kubernetes cluster kubeconfig save ${cluster.shortName}`);
// get K8S context
context = await (0, kube_config_1.getKubeContextByCluster)(cluster);
if (context) {
cluster = await DB.updateOne("cluster", { slug: clusterSlug }, { contextName: context.name }, { ownership: options.ownership });
}
else {
throw new Error(`Context of "${clusterSlug}" cluster not found.`);
}
// switch context (if needed)
// if (shouldSwitchContextToThisCluster) await switchContext(context.name);
// mark this cluster verified
cluster = await DB.updateOne("cluster", { slug: clusterSlug }, { isVerified: true });
(0, log_1.logSuccess)(`[CLUSTER MANAGER] ✓ Connected to "${clusterSlug}" cluster.`);
return cluster;
case "custom":
// Only support "kube-config" authentication
const { kubeConfig } = cluster;
if (cluster.isVerified && !kubeConfig)
throw new Error(`Permissions denied, please contact your administrator.`);
if (!kubeConfig)
throw new Error(`This cluster doesn't have any "kube-config" data to authenticate.`);
filePath = (0, plugins_1.createTmpFile)(`${clusterSlug}-kube-config.yaml`, kubeConfig);
// start authenticating & save cluster access info to "kubeconfig"...
cluster = await custom_1.default.authenticate(cluster, { filePath, isDebugging, ownership: options.ownership });
if (!cluster)
throw new Error(`Unable to authenticate this cluster: ${cluster.name}`);
const { contextName, isVerified } = cluster;
if (!contextName)
throw new Error(`Context of "${clusterSlug}" cluster not found.`);
if (!isVerified)
throw new Error(`Unable to connect to "${clusterSlug}" cluster.`);
// delete temporary file
(0, fs_1.unlink)(filePath, (err) => err && (0, log_1.logError)(`[CLUSTER AUTH] Remove tmp file:`, err));
// switch context (if needed)
// if (shouldSwitchContextToThisCluster) await switchContext(contextName);
(0, log_1.logSuccess)(`[CLUSTER MANAGER] ✓ Connected to "${clusterSlug}" cluster.`);
return cluster;
default:
throw new Error(`❌ This provider (${providerShortName}) is not supported yet.`);
}
};
exports.authCluster = authCluster;
/**
* Authenticate current machine with the K8S cluster by its short name (context-name).
* @param clusterSlug - A cluster name on the cloud provider (**NOT** a cluster in `kubeconfig`)
*/
const authClusterBySlug = async (clusterSlug, options) => {
if (!clusterSlug)
throw new Error(`Param "clusterSlug" is required.`);
// find the cluster in the database:
const { DB } = await Promise.resolve().then(() => __importStar(require("../../modules/api/DB")));
let cluster = await DB.findOne("cluster", { slug: clusterSlug });
if (!cluster) {
throw new Error(`This cluster (${clusterSlug}) is not existed, please contact your administrator or register a new one with the CLI command.`);
}
return (0, exports.authCluster)(cluster, options);
};
exports.authClusterBySlug = authClusterBySlug;
exports.default = exports.authCluster;