Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): implement chart install, uninstall and upgrade commands #454

Merged
merged 24 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
550d2e4
fix: setup constants and log into tmp log files
leninmehedy Oct 24, 2023
19a9e4b
feat(cli): initial implementation of cluster commands
leninmehedy Oct 24, 2023
9dbf5f2
feat(cli): implement cluster list and info commands
leninmehedy Oct 24, 2023
aa46f8c
fix: remove redundant function param
leninmehedy Oct 24, 2023
10c6c91
fix: show init status to user after execution
leninmehedy Oct 24, 2023
600bad4
fix: polish usage desc
leninmehedy Oct 24, 2023
d3ad77a
fix: update user log
leninmehedy Oct 24, 2023
b29f1ce
feat: add colors in console messages.
leninmehedy Oct 24, 2023
c92c3ff
fix: reduce noise in log file because of chalk
leninmehedy Oct 24, 2023
c82af9a
style: update log message
leninmehedy Oct 24, 2023
db5763b
doc: add comment and code cleanup
leninmehedy Oct 24, 2023
b6858f0
fix: remove redundant message during delete to avoid confusion
leninmehedy Oct 24, 2023
85b9af9
style: polishing
leninmehedy Oct 24, 2023
d9ee506
fix: rename TMP_DIR to FST_HOME_DIR
leninmehedy Oct 24, 2023
f2150ad
feat: create a custom logger embedding the winston logger and use non…
leninmehedy Oct 24, 2023
a4c4140
fix: logger debug method
leninmehedy Oct 25, 2023
93a0724
feat: scaffold network deploy command
leninmehedy Oct 25, 2023
7efc0fe
feat: implement cluster setup
leninmehedy Oct 25, 2023
fe46be5
feat(cli): implement network deploy command
leninmehedy Oct 26, 2023
d9a3362
Merge branch 'main' into 448-cli-deploy-network-command
leninmehedy Oct 26, 2023
4d53b90
feat: implement chart install, uninstall and upgrade commands
leninmehedy Oct 26, 2023
f8d2cb5
fix: remove redundant log
leninmehedy Oct 26, 2023
780e897
fix: command desc
leninmehedy Oct 26, 2023
34f6715
style: code cleanup
leninmehedy Oct 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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