Skip to content

Commit

Permalink
feat(cli): implement chart install, uninstall and upgrade commands (#454
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 26, 2023
1 parent bf7f6ff commit 70fd199
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 92 deletions.
102 changes: 102 additions & 0 deletions fullstack-network-manager/src/commands/base.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,108 @@ export const BaseCommand = class BaseCommand {
})
}

/**
* List available clusters
* @returns {Promise<string[]>}
*/
async getInstalledCharts(namespaceName) {
try {
let cmd = `helm list -n ${namespaceName} -q`

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

return output.split(/\r?\n/)
} catch (e) {
this.logger.error("%s", e)
this.logger.showUser(e.message)
}

return []
}

async chartInstall(namespaceName, releaseName, chartPath, valuesArg) {
try {
this.logger.showUser(chalk.cyan(`Setting up FST network...`))

let charts= await this.getInstalledCharts(namespaceName)
if (!charts.includes(releaseName)) {
let cmd = `helm install -n ${namespaceName} ${releaseName} ${chartPath} ${valuesArg}`
this.logger.showUser(chalk.cyan(`Installing ${releaseName} chart`))

let output = await this.runExec(cmd)
this.logger.showUser(chalk.green('OK'), `chart '${releaseName}' is installed`)
} else {
this.logger.showUser(chalk.green('OK'), `chart '${releaseName}' is already installed`)
}

this.logger.showUser(chalk.yellow("Chart setup is complete"))

return true
} catch (e) {
this.logger.error("%s", e.stack)
this.logger.showUser(e.message)
}

return false
}

async chartUninstall(namespaceName, releaseName) {
try {
this.logger.showUser(chalk.cyan(`Uninstalling FST network ...`))

let charts= await this.getInstalledCharts(namespaceName)
if (charts.includes(releaseName)) {
let cmd = `helm uninstall ${releaseName} -n ${namespaceName}`
this.logger.showUser(chalk.cyan(`Uninstalling ${releaseName} chart`))

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

this.logger.showUser(chalk.yellow("Chart uninstallation is complete"))

return true
} catch (e) {
this.logger.error("%s", e.stack)
this.logger.showUser(e.message)
}

return false
}

async chartUpgrade(namespaceName, releaseName, chartPath, valuesArg) {
try {
this.logger.showUser(chalk.cyan(`Upgrading FST network deployment chart ...`))

let charts= await this.getInstalledCharts(namespaceName)
if (charts.includes(releaseName)) {
let cmd = `helm upgrade ${releaseName} -n ${namespaceName} ${chartPath} ${valuesArg}`
this.logger.showUser(chalk.cyan(`Upgrading ${releaseName} chart`))

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

this.logger.showUser(chalk.yellow("Chart upgrade is complete"))
} else {
this.logger.showUser(chalk.green('OK'), `chart '${releaseName}' is not installed`)
return false
}

return true
} catch (e) {
this.logger.error("%s", e.stack)
this.logger.showUser(e.message)
}

return false
}


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

Expand Down
115 changes: 115 additions & 0 deletions fullstack-network-manager/src/commands/chart.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import {BaseCommand} from "./base.mjs";
import chalk from "chalk";
import * as core from "../core/index.mjs";
import * as flags from "./flags.mjs";


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

prepareValuesArg(argv) {
let {valuesFile, mirrorNode, hederaExplorer} = argv
let valuesArg = `--values ${this.chartPath}/values.yaml`

if (valuesFile) {
valuesArg += ` --values ${valuesFile}`
}

valuesArg += ` --set hedera-mirror-node.enable=${mirrorNode} --set hedera-explorer.enable=${hederaExplorer}`

return valuesArg
}

async install(argv) {
let namespace = argv.namespace
let valuesArg = this.prepareValuesArg(argv)

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

async uninstall(argv) {
let namespace = argv.namespace

return await this.chartUninstall(namespace, this.releaseName)
}

async upgrade(argv) {
let namespace = argv.namespace
let valuesArg = this.prepareValuesArg(argv)

return await this.chartUpgrade(namespace, this.releaseName, this.chartPath, valuesArg)
}

static getCommandDefinition(chartCmd) {
return {
command: 'chart',
desc: 'Manage FST chart deployment',
builder: yargs => {
return yargs
.command({
command: 'install',
desc: 'Install FST network deployment chart',
builder: yargs => {
yargs.option('namespace', flags.namespaceFlag)
yargs.option('mirror-node', flags.deployMirrorNode)
yargs.option('hedera-explorer', flags.deployHederaExplorer)
yargs.option('values-file', flags.valuesFile)
},
handler: argv => {
chartCmd.logger.debug("==== Running 'chart install' ===")
chartCmd.logger.debug(argv)

chartCmd.install(argv).then(r => {
chartCmd.logger.debug("==== Finished running `chart install`====")

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

}
})
.command({
command: 'uninstall',
desc: 'Uninstall FST network deployment chart',
builder: yargs => {
yargs.option('namespace', flags.namespaceFlag)
},
handler: argv => {
chartCmd.logger.debug("==== Running 'chart uninstall' ===")
chartCmd.logger.debug(argv)

chartCmd.uninstall(argv).then(r => {
chartCmd.logger.debug("==== Finished running `chart uninstall`====")

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

}
})
.command({
command: 'upgrade',
desc: 'Refresh existing FST network deployment with new values',
builder: yargs => {
yargs.option('namespace', flags.namespaceFlag)
yargs.option('mirror-node', flags.deployMirrorNode)
yargs.option('hedera-explorer', flags.deployHederaExplorer)
yargs.option('values-file', flags.valuesFile)
},
handler: argv => {
chartCmd.logger.debug("==== Running 'chart upgrade' ===")
chartCmd.logger.debug(argv)

chartCmd.upgrade(argv).then(r => {
chartCmd.logger.debug("==== Finished running `chart upgrade`====")

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

}
})
.demand(1, 'Select a chart command')
}
}
}
}
40 changes: 14 additions & 26 deletions fullstack-network-manager/src/commands/cluster.mjs
Original file line number Diff line number Diff line change
@@ -1,24 +1,8 @@
import * as core from '../core/index.mjs'
import * as flags from './flags.mjs'
import {BaseCommand} from "./base.mjs";
import chalk from "chalk";

/**
* Flags for 'cluster' command
*/
const clusterNameFlag = {
describe: 'Name of the cluster',
default: core.constants.CLUSTER_NAME,
alias: 'c',
type: 'string'
}

const namespaceFlag = {
describe: 'Name of the namespace',
default: core.constants.NAMESPACE_NAME,
alias: 's',
type: 'string'
}

/**
* Define the core functionalities of 'cluster' command
*/
Expand Down Expand Up @@ -191,7 +175,7 @@ export const ClusterCommand = class extends BaseCommand {
command: 'create',
desc: 'Create a cluster',
builder: yargs => {
yargs.option('cluster-name', clusterNameFlag)
yargs.option('cluster-name', flags.clusterNameFlag)
},
handler: argv => {
clusterCmd.logger.debug("==== Running 'cluster create' ===")
Expand All @@ -208,17 +192,18 @@ export const ClusterCommand = class extends BaseCommand {
command: 'delete',
desc: 'Delete a cluster',
builder: yargs => {
yargs.option('cluster-name', clusterNameFlag)
yargs.option('cluster-name', flags.clusterNameFlag)
},
handler: argv => {
clusterCmd.logger.debug("==== Running 'cluster delete' ===")
clusterCmd.logger.debug(argv)

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

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

clusterCmd.logger.debug("==== Finished running `cluster delete`====")
}
})
.command({
Expand All @@ -229,45 +214,48 @@ export const ClusterCommand = class extends BaseCommand {
clusterCmd.logger.debug(argv)

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

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

clusterCmd.logger.debug("==== Finished running `cluster list`====")
}
})
.command({
command: 'info',
desc: 'Get cluster info',
builder: yargs => {
yargs.option('cluster-name', clusterNameFlag)
yargs.option('cluster-name', flags.clusterNameFlag)
},
handler: argv => {
clusterCmd.logger.debug("==== Running 'cluster info' ===")
clusterCmd.logger.debug(argv)

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

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

clusterCmd.logger.debug("==== Finished running `cluster info`====")
}
})
.command({
command: 'setup',
desc: 'Setup cluster with shared components',
builder: yargs => {
yargs.option('cluster-name', clusterNameFlag)
yargs.option('namespace', namespaceFlag)
yargs.option('cluster-name', flags.clusterNameFlag)
yargs.option('namespace', flags.namespaceFlag)
},
handler: argv => {
clusterCmd.logger.debug("==== Running 'cluster setup' ===")
clusterCmd.logger.debug(argv)

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

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

clusterCmd.logger.debug("==== Finished running `cluster setup`====")
}
})
.demand(1, 'Select a cluster command')
Expand Down
37 changes: 37 additions & 0 deletions fullstack-network-manager/src/commands/flags.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as core from "../core/index.mjs";

// list of common flags across commands. command specific flags are defined in the command's module.
export const clusterNameFlag = {
describe: 'Cluster name',
default: core.constants.CLUSTER_NAME,
alias: 'c',
type: 'string'
}

export const namespaceFlag = {
describe: 'Namespace',
default: core.constants.NAMESPACE_NAME,
alias: 's',
type: 'string'
}

export const deployMirrorNode = {
describe: 'Deploy mirror node',
default: true,
alias: 'm',
type: 'boolean'
}

export const deployHederaExplorer = {
describe: 'Deploy hedera explorer',
default: true,
alias: 'x',
type: 'boolean'
}

export const valuesFile = {
describe: 'Helm chart values file [ to override defaults ]',
default: "",
alias: 'f',
type: 'string'
}
6 changes: 3 additions & 3 deletions fullstack-network-manager/src/commands/index.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ClusterCommand} from "./cluster.mjs";
import {InitCommand} from "./init.mjs";
import {NetworkCommand} from "./network.mjs"
import {ChartCommand} from "./chart.mjs"

/*
* Return a list of Yargs command builder to be exposed through CLI
Expand All @@ -9,12 +9,12 @@ import {NetworkCommand} from "./network.mjs"
function Initialize(opts) {
const initCmd = new InitCommand(opts)
const clusterCmd = new ClusterCommand(opts)
const networkCmd = new NetworkCommand(opts)
const chartCmd = new ChartCommand(opts)

return [
InitCommand.getCommandDefinition(initCmd),
ClusterCommand.getCommandDefinition(clusterCmd),
NetworkCommand.getCommandDefinition(networkCmd),
ChartCommand.getCommandDefinition(chartCmd),
]
}

Expand Down
Loading

0 comments on commit 70fd199

Please sign in to comment.