kubecfg
Version:
Helper tool to configure environment variables for Kubectl
496 lines (360 loc) • 14.2 kB
text/typescript
import * as program from "commander";
import * as fs from "fs";
import * as path from "path";
import * as os from "os";
import * as yaml from "js-yaml";
import * as random from "randomstring";
import {functionWalker} from "./walker";
const execFile = require('child_process').execFile;
interface config{
currentFile: string
}
export default class kubecfg {
private _argv: string;
private _isWin: boolean;
private _basePath: string;
private _configPath: string;
private _configFile: string;
constructor(argv) {
this._argv = argv;
this._isWin = process.platform === "win32";
this._basePath = path.join(os.homedir(), ".kube");
this._configPath = path.join(os.homedir(), ".kconfig");
if(!fs.existsSync(this._configPath)){
fs.mkdirSync(this._configPath);
}
if(!fs.existsSync(this._basePath)){
fs.mkdirSync(this._basePath);
}
this._configFile = path.join(os.homedir(), ".kconfig", "config.yaml");
this._process(argv);
}
private _process(argv) {
program
//set base path
//copy file to base
//set context
.option('-c, --copy [file]', 'Copy a file to the Kubectl environment')
.option('-u, --use [context]', 'Change the current context. Pass in a filename or context name')
//.option('-r, --remove [file]', 'Remove a file from the Kubectl environment')
.option('-s, --show', 'Show the current config')
.option('-l, --list', 'List all configs')
.option('-r, --reset', "Clear the config and go back to kube defaults")
//.option('-w, --working', 'Set the config base working folder')
.parse(argv);
}
public Process(): Promise<boolean> {
return new Promise<boolean>(async (good, bad) => {
if (program.copy) {
await this._copyFile(program.copy);
good(true);
return;
}
if(program.list)
{
await this._list();
return;
}
if(program.use){
await this._use(program.use);
return;
}
if(program.show){
this._show();
return;
}
if(program.reset){
this._reset();
return;
}
this._show();
});
}
private _reset(){
var script = path.join(this._configPath, "kubeconfigexport.sh");
fs.writeFileSync(script, "");
console.log("Cleared. Remember to reload your shell or run . ~/.bashrc")
var conf = this._getConfig();
conf.currentFile = "";
this._setConfig(conf);
}
private _export(){
var file = this._show();
if(!file){
return;
}
var script = path.join(this._configPath, "kubeconfigexport.sh");
var bash = `#!/bin/bash\nexport KUBECONFIG=${file}\n`;
fs.writeFileSync(script, bash);
fs.chmodSync(script, "777");
var rc = path.join(os.homedir(), ".bashrc");
if(fs.existsSync(rc)){
var rc = fs.readFileSync(rc, "utf-8");
if(rc.indexOf("kubeconfigexport.sh") == -1){
console.log("");
console.log(`Please update your ~/.bashrc file by adding . ${script} to your `);
console.log(`Run this update ~/.bashrc -> echo ". ${script}" >> ~/.bashrc && source ~/.bashrc`)
}
}
console.log("");
console.log(`Remember to reload your shell or run . ~/.bashrc`);
}
private _show():string{
var file = this._getConfig().currentFile;
if(!file || file == ""){
console.log("kubecfg: Nothing set, using kube defaults");
return null;
}
if(!fs.existsSync(file)){
console.log(`File set to ${file} which DOES NOT EXIST, using kube defaults`);
return null;
}
var doc = this._readFile(file);
if(!doc){
console.log(`Could not read ${file}. Perhaps file is borked`);
return null;
}
var context = doc["current-context"];
if(!context){
console.log(`Could not read set context in ${file}. Perhaps file is borked`);
return null;
}
console.log(`Current context is ${context} in ${file}`);
return file;
}
private async _use(setContext:string){
var files = await this._walk();
for(var f in files){
var file = files[f];
if(file === setContext){
this._set(setContext, null);
return;
}
var doc = this._readFile(file);
if(doc.contexts && doc.contexts.length > 0){
for(var c in doc.contexts){
var context = doc.contexts[c];
if(context.name == setContext){
this._set(file, setContext);
this._export();
return;
}
}
}
}
console.log(`Could not find any context or file named ${setContext}`);
}
private _set(file:string, setContext:string){
if(!fs.existsSync(file)){
return;
}
var doc = this._readFile(file);
for(var c in doc.contexts){
var context = doc.contexts[c];
if(context.name == setContext){
doc["current-context"] = setContext;
}
}
var d:string;
if(file.toLowerCase().endsWith('json')){
d = JSON.stringify(doc);
}else{
d = yaml.safeDump(doc);
}
fs.writeFileSync(file, d);
var conf = this._getConfig();
conf.currentFile = file;
this._setConfig(conf);
}
private _getConfig(): config{
var conf: config;
if(!fs.existsSync(this._configFile)){
conf = {
currentFile: ""
}
}else{
conf = this._readFile(this._configFile);
}
return conf;
}
private _setConfig(conf:config){
var conf = yaml.safeDump(conf);
fs.writeFileSync(this._configFile, conf);
}
private async _list(){
var files = await this._walk();
for(var f in files){
var file = files[f];
var doc = this._readFile(file);
if(!doc){
continue;
}
if(doc.contexts && doc.contexts.length > 0){
for(var c in doc.contexts){
var context = doc.contexts[c];
console.log(`${context.name} in ${file}`);
}
}
}
}
private _readFile(file:string):any{
if(!fs.existsSync(file))
{
return null;
}
try{
var doc = yaml.safeLoad(fs.readFileSync(file, 'utf8'));
return doc;
}catch(e){
console.log(`Could not load ${file}`);
}
}
private async _walk(): Promise<Array<string>>{
var fw = new functionWalker(this._basePath);
var files = await fw.doWalk();
return files;
}
private _copyFile(file:string){
if(!fs.existsSync(file)){
console.log(`File not found: ${file}`);
return;
}
var fn = path.basename(file);
var target = path.join(this._basePath, fn);
while(fs.existsSync(target)){
var rnd = random.generate({
length: 5,
charset: 'alphabetic'
});
target = path.join(this._basePath, fn);
if(target.indexOf(".")!=-1){
var ext = target.split('.').pop();
var targetNoExt = target.replace(`.${ext}`, '');
target = `${targetNoExt}_${rnd}.${ext}`;
}else{
target += rnd;
}
console.log(`File exists at target, modifying to: ${target}`);
}
fs.copyFileSync(file, target, );
console.log(`Copied to : ${target}`);
}
// private _showVars():Promise<string> {
// return new Promise<string>(async (good, bad)=>{
// var current_config = "";
// if (this._isWin) {
// current_config = await this._runPowershell('[System.Environment]::GetEnvironmentVariable("KUBECONFIG","User")');
// } else {
// current_config = await this._runBash('. ~/.bashrc | echo $KUBECONFIG');
// }
// console.log(`Current config: ${current_config}`);
// good(current_config);
// });
// }
// private _processWindows(add: string, remove: string): Promise<boolean> {
// return new Promise<boolean>(async (good, bad) => {
// try {
// var current_config = await this._showVars();
// current_config = current_config.replace(/^\n+|\n+$/g, '');
// current_config = current_config.replace(/^\r+|\r+$/g, '');
// if (!current_config) {
// current_config = "";
// }
// if (add != null) {
// if (current_config.indexOf(add) == -1) {
// current_config += `;${add}`;
// }
// }
// if (remove != null) {
// current_config = current_config.replace(remove, "");
// current_config = current_config.replace(";;", ";");
// }
// current_config = current_config.replace(/^;+|;+$/g, '');
// console.log(`Setting config: ${current_config}`);
// var run_current_config = `[Environment]::SetEnvironmentVariable("KUBECONFIG", "${current_config}", "User")`;
// var resultUpdate = await this._runPowershell(run_current_config);
// // var resultUpdate = await this._runPowershell('$Env:KUBECONFIG = [System.Environment]::GetEnvironmentVariable("KUBECONFIG","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("KUBECONFIG","User")');
// console.log('Now run: $Env:KUBECONFIG = [System.Environment]::GetEnvironmentVariable("KUBECONFIG","User")');
// good(true);
// } catch (e) {
// console.log(e);
// bad(e);
// }
// });
// }
// private async _runBash(command: string): Promise<string> {
// return new Promise<string>((good, bad) => {
// var result = execFile("bash", ["-c", command], (error, stdout, stderr) => {
// if (!error) {
// good(stdout);
// } else {
// bad(stderr);
// }
// });
// });
// }
// private async _runPowershell(command: string): Promise<string> {
// return new Promise<string>((good, bad) => {
// var result = execFile("powershell", ["-Command", command], (error, stdout, stderr) => {
// if (!error) {
// good(stdout);
// } else {
// bad(stderr);
// }
// });
// });
// }
// private async _processLinux(add: string, remove: string) {
// //console.log("********" + process.env.KUBECONFIG);
// //console.log(add);
// var f = path.join(path.resolve(process.env.HOME, ".bashrc"));
// var fcontents = "";
// if (fs.existsSync) {
// fcontents = fs.readFileSync(f, 'utf8');
// }
// var current_config = await this._showVars();
// if (!current_config) {
// current_config = "";
// }
// current_config = current_config.trim();
// if (add != null) {
// if (current_config.indexOf(add) == -1) {
// current_config += `:${add}`;
// }
// }
// if (remove != null) {
// current_config = current_config.replace(remove, "");
// }
// if (current_config.trim() != "") {
// current_config = `export KUBECONFIG=${current_config}\n`;
// }
// current_config = current_config.replace("::", ":");
// current_config = current_config.replace(/^:+|:+(\n?)$/g, '');
// //find current in the bashrc, if there, kill that line
// //the current set config is king
// var finalcontents = "";
// if (fcontents.indexOf("KUBECONFIG") != -1) {
// finalcontents = fcontents.replace(/(\n)((.*?)KUBECONFIG.*?\n)/gi, `\n${current_config}`);
// } else {
// finalcontents = fcontents + `\n\n#Kubectl configuration\n${current_config}`;
// }
// //console.log(finalcontents);
// fs.writeFileSync(f, finalcontents);
// console.log(`Set: ${current_config}`);
// console.log("Run '. ~/.bashrc' now to refresh your environment.")
// }
// private _tryFixFile(file): string {
// if (this._isWin) {
// var home = os.homedir();
// if (file != null) {
// file = file.replace("~", home);
// }
// }
// var full = path.resolve(file);
// if (fs.existsSync(full)) {
// return full;
// }
// return null;
// }
}