Skip to content

Commit

Permalink
fix(cli): encapsulate Kind commands in a separate wrapper class (#468)
Browse files Browse the repository at this point in the history
Signed-off-by: Lenin Mehedy <lenin.mehedy@swirldslabs.com>
  • Loading branch information
leninmehedy authored Oct 31, 2023
1 parent 0313c3a commit 6dc6025
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 72 deletions.
1 change: 1 addition & 0 deletions fullstack-network-manager/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test/*
2 changes: 1 addition & 1 deletion fullstack-network-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"access": "public"
},
"scripts": {
"test": "jest"
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
},
"keywords": [
"fullstack-network-manager",
Expand Down
46 changes: 13 additions & 33 deletions fullstack-network-manager/src/commands/base.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
import {exec} from "child_process";
import * as core from "../core/index.mjs"
import chalk from "chalk";
import {ShellRunner} from "../core/shell_runner.mjs";

export const BaseCommand = class BaseCommand {
async checkDep(dep) {
export class BaseCommand extends ShellRunner {
async checkDep(cmd) {
try {
await this.runExec(dep)
this.logger.debug(cmd)
await this.run(cmd)
} catch (e) {
this.logger.error("%s", e)
return false
Expand All @@ -19,23 +21,23 @@ export const BaseCommand = class BaseCommand {
* @returns {Promise<boolean>}
*/
async checkKind() {
return this.checkDep(core.constants.KIND)
return this.checkDep(`${core.constants.KIND} --version`)
}

/**
* Check if 'helm' CLI program is installed or not
* @returns {Promise<boolean>}
*/
async checkHelm() {
return this.checkDep(core.constants.HELM)
return this.checkDep(`${core.constants.HELM} version`)
}

/**
* Check if 'kubectl' CLI program is installed or not
* @returns {Promise<boolean>}
*/
async checkKubectl() {
return this.checkDep(core.constants.KUBECTL)
return this.checkDep(`${core.constants.KUBECTL} version`)
}

/**
Expand Down Expand Up @@ -69,26 +71,6 @@ export const BaseCommand = class BaseCommand {
return true
}

/**
* Run the specified bash command
* @param cmd is a bash command including args
* @returns {Promise<string>}
*/
runExec(cmd) {
let self = this

return new Promise((resolve, reject) => {
self.logger.debug(`Invoking '${cmd}'...`)
exec(cmd, (error, stdout, stderr) => {
if (error) {
reject(error)
}

resolve(stdout)
})
})
}

/**
* List available clusters
* @returns {Promise<string[]>}
Expand All @@ -97,7 +79,7 @@ export const BaseCommand = class BaseCommand {
try {
let cmd = `helm list -n ${namespaceName} -q`

let output = await this.runExec(cmd)
let output = await this.run(cmd)
this.logger.showUser("\nList of installed charts\n--------------------------\n%s", output)

return output.split(/\r?\n/)
Expand All @@ -118,7 +100,7 @@ export const BaseCommand = class BaseCommand {
let cmd = `helm install -n ${namespaceName} ${releaseName} ${chartPath} ${valuesArg}`
this.logger.showUser(chalk.cyan(`Installing ${releaseName} chart`))

let output = await this.runExec(cmd)
let output = await this.run(cmd)
this.logger.showUser(chalk.green('OK'), `chart '${releaseName}' is installed`)
} else {
this.logger.showUser(chalk.green('OK'), `chart '${releaseName}' is already installed`)
Expand All @@ -144,7 +126,7 @@ export const BaseCommand = class BaseCommand {
let cmd = `helm uninstall ${releaseName} -n ${namespaceName}`
this.logger.showUser(chalk.cyan(`Uninstalling ${releaseName} chart`))

let output = await this.runExec(cmd)
let output = await this.run(cmd)
this.logger.showUser(chalk.green('OK'), `chart '${releaseName}' is uninstalled`)
await this.getInstalledCharts(namespaceName)
} else {
Expand All @@ -171,7 +153,7 @@ export const BaseCommand = class BaseCommand {
let cmd = `helm upgrade ${releaseName} -n ${namespaceName} ${chartPath} ${valuesArg}`
this.logger.showUser(chalk.cyan(`Upgrading ${releaseName} chart`))

let output = await this.runExec(cmd)
let output = await this.run(cmd)
this.logger.showUser(chalk.green('OK'), `chart '${releaseName}' is upgraded`)
await this.getInstalledCharts(namespaceName)

Expand All @@ -192,9 +174,7 @@ export const BaseCommand = class BaseCommand {


constructor(opts) {
if (opts.logger === undefined) throw new Error("logger cannot be null")

this.logger = opts.logger
super(opts);

// map of dependency checks
this.checks = new Map()
Expand Down
4 changes: 2 additions & 2 deletions fullstack-network-manager/src/commands/chart.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as core from "../core/index.mjs";
import * as flags from "./flags.mjs";


export const ChartCommand = class ChartCommand extends BaseCommand {
export class ChartCommand extends BaseCommand {
chartPath = `${core.constants.FST_HOME_DIR}/full-stack-testing/charts/fullstack-deployment`
releaseName = "fullstack-deployment"

Expand All @@ -25,7 +25,7 @@ export const ChartCommand = class ChartCommand extends BaseCommand {
let namespace = argv.namespace
let valuesArg = this.prepareValuesArg(argv)

await this.runExec(`helm dependency update ${this.chartPath}`)
await this.run(`helm dependency update ${this.chartPath}`)
return await this.chartInstall(namespace, this.releaseName, this.chartPath, valuesArg)
}

Expand Down
66 changes: 41 additions & 25 deletions fullstack-network-manager/src/commands/cluster.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,25 @@ import * as core from '../core/index.mjs'
import * as flags from './flags.mjs'
import {BaseCommand} from "./base.mjs";
import chalk from "chalk";
import {Kind} from "../core/kind.mjs";

/**
* Define the core functionalities of 'cluster' command
*/
export const ClusterCommand = class extends BaseCommand {
export class ClusterCommand extends BaseCommand {

constructor(opts) {
super(opts);
this.kind = new Kind(opts)
}

/**
* List available clusters
* @returns {Promise<string[]>}
*/
async getClusters() {
try {
let cmd = `kind get clusters -q`

let output = await this.runExec(cmd)
this.logger.showUser("\nList of available clusters \n--------------------------\n%s", output)

return output.split(/\r?\n/)
return await this.kind.getClusters('-q')
} catch (e) {
this.logger.error("%s", e)
this.logger.showUser(e.message)
Expand All @@ -37,10 +38,10 @@ export const ClusterCommand = class extends BaseCommand {
try {
let clusterName = argv.clusterName
let cmd = `kubectl cluster-info --context kind-${clusterName}`
let output = await this.run(cmd)

let output = await this.runExec(cmd)
this.logger.showUser(output)

this.logger.showUser(`\nCluster information (${clusterName})\n---------------------------------------`)
output.forEach(line => this.logger.showUser(line))
return true
} catch (e) {
this.logger.error("%s", e)
Expand All @@ -50,6 +51,11 @@ export const ClusterCommand = class extends BaseCommand {
return false
}

async showClusterList(argv) {
let clusters = await this.getClusters()
this.logger.showUser("\nList of available clusters \n---------------------------------------")
clusters.forEach(name => this.logger.showUser(name))
}
/**
* Create a cluster
* @param argv
Expand All @@ -58,15 +64,20 @@ export const ClusterCommand = class extends BaseCommand {
async create(argv) {
try {
let clusterName = argv.clusterName
let cmd = `kind create cluster -n ${clusterName} --config ${core.constants.RESOURCES_DIR}/dev-cluster.yaml`

this.logger.showUser(chalk.cyan('Creating cluster:'), chalk.yellow(`${clusterName}...`))
let output = await this.runExec(cmd)
this.logger.debug(output)
this.logger.showUser(chalk.green('Created cluster:'), chalk.yellow(clusterName))
let clusters = await this.getClusters()

if (!clusters.includes(clusterName)) {
this.logger.showUser(chalk.cyan('Creating cluster:'), chalk.yellow(`${clusterName}...`))
await this.kind.createCluster(
`-n ${clusterName}`,
`--config ${core.constants.RESOURCES_DIR}/dev-cluster.yaml`,
)
this.logger.showUser(chalk.green('Created cluster:'), chalk.yellow(clusterName))
}

// show all clusters and cluster-info
await this.getClusters()
await this.showClusterList()

await this.getClusterInfo(argv)

return true
Expand All @@ -86,11 +97,15 @@ export const ClusterCommand = class extends BaseCommand {
async delete(argv) {
try {
let clusterName = argv.clusterName
let cmd = `kind delete cluster -n ${clusterName}`
let clusters = await this.getClusters()
if (clusters.includes(clusterName)) {
this.logger.showUser(chalk.cyan('Deleting cluster:'), chalk.yellow(`${clusterName}...`))
await this.kind.deleteCluster(clusterName)
await this.showClusterList()
} else {
this.logger.showUser(`Cluster '${clusterName}' does not exist`)
}

this.logger.showUser(chalk.cyan('Deleting cluster:'), chalk.yellow(`${clusterName}...`))
await this.runExec(cmd)
await this.getClusters()

return true
} catch (e) {
Expand All @@ -110,7 +125,7 @@ export const ClusterCommand = class extends BaseCommand {
let namespaceName = argv.namespace
let cmd = `helm list -n ${namespaceName} -q`

let output = await this.runExec(cmd)
let output = await this.run(cmd)
this.logger.showUser("\nList of installed charts\n--------------------------\n%s", output)

return output.split(/\r?\n/)
Expand Down Expand Up @@ -144,7 +159,7 @@ export const ClusterCommand = class extends BaseCommand {
this.logger.showUser(chalk.cyan("Installing fullstack-cluster-setup chart"))
this.logger.debug(`Invoking '${cmd}'...`)

let output = await this.runExec(cmd)
let output = await this.run(cmd)
this.logger.showUser(chalk.green('OK'), `chart '${releaseName}' is installed`)
} else {
this.logger.showUser(chalk.green('OK'), `chart '${releaseName}' is already installed`)
Expand Down Expand Up @@ -182,10 +197,11 @@ export const ClusterCommand = class extends BaseCommand {
clusterCmd.logger.debug(argv)

clusterCmd.create(argv).then(r => {
clusterCmd.logger.debug("==== Finished running `cluster create`====")

if (!r) process.exit(1)
})

clusterCmd.logger.debug("==== Finished running `cluster create`====")
}
})
.command({
Expand Down Expand Up @@ -213,7 +229,7 @@ export const ClusterCommand = class extends BaseCommand {
clusterCmd.logger.debug("==== Running 'cluster list' ===")
clusterCmd.logger.debug(argv)

clusterCmd.getClusters().then(r => {
clusterCmd.showClusterList().then(r => {
clusterCmd.logger.debug("==== Finished running `cluster list`====")

if (!r) process.exit(1)
Expand Down
2 changes: 1 addition & 1 deletion fullstack-network-manager/src/commands/init.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import chalk from "chalk";
/**
* Defines the core functionalities of 'init' command
*/
export const InitCommand = class extends BaseCommand {
export class InitCommand extends BaseCommand {
/**
* Executes the init CLI command
* @returns {Promise<boolean>}
Expand Down
Loading

0 comments on commit 6dc6025

Please sign in to comment.