Skip to content

Commit

Permalink
feat(cli): implement cluster create and delete commands (#446)
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 9c6930e commit 78be823
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 91 deletions.
7 changes: 7 additions & 0 deletions fullstack-network-manager/resources/dev-cluster.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: fst # this is overridden if CLUSTER_NAME env var is set. Check .env file
nodes:
- role: control-plane
labels:
fullstack-scheduling.io/role: network
57 changes: 20 additions & 37 deletions fullstack-network-manager/src/commands/base.mjs
Original file line number Diff line number Diff line change
@@ -1,57 +1,41 @@
"use strict"
import {exec} from "child_process";
import * as core from "../core/index.mjs"
import chalk from "chalk";

export const BaseCommand = class BaseCommand {
/**
* Check if 'kind' CLI program is installed or not
* @returns {Promise<boolean>}
*/
async checkKind() {
async checkDep(dep) {
try {
this.logger.debug("Checking if 'kind' is installed")
await this.runExec("kind --version")
this.logger.debug("OK: 'kind' is installed")
await this.runExec(dep)
} catch (e) {
this.logger.error("%s", e)
return false
}

return true
}
/**
* Check if 'kind' CLI program is installed or not
* @returns {Promise<boolean>}
*/
async checkKind() {
return this.checkDep(core.constants.KIND)
}

/**
* Check if 'helm' CLI program is installed or not
* @returns {Promise<boolean>}
*/
async checkHelm() {
try {
this.logger.debug("Checking if 'helm' is installed")
await this.runExec("helm version")
this.logger.debug("OK: 'helm' is installed")
} catch (e) {
this.logger.error("%s", e)
return false
}

return true
return this.checkDep(core.constants.HELM)
}

/**
* Check if 'kubectl' CLI program is installed or not
* @returns {Promise<boolean>}
*/
async checkKubectl() {
try {
this.logger.debug("Checking if 'kubectl' is installed")
await this.runExec("kubectl version")
this.logger.debug("OK: 'kubectl' is installed")
} catch (e) {
this.logger.error("%s", e)
return false
}

return true
return this.checkDep(core.constants.KUBECTL)
}

/**
Expand All @@ -60,29 +44,28 @@ export const BaseCommand = class BaseCommand {
* @returns {Promise<boolean>}
*/
async checkDependencies(deps = []) {
this.logger.info("Checking for required dependencies: %s", deps)
this.logger.debug("Checking for required dependencies: %s", deps)

for (let i = 0; i < deps.length; i++) {
let dep = deps[i]
this.logger.debug("Checking for dependency '%s'", dep)

let status = false
let check = this.checks.get(dep)
if (!check) {
this.logger.error("FAIL: Dependency '%s' is unknown", dep)
return false
if (check) {
status = await check()
}


let status = await check()
if (!status) {
this.logger.error("FAIL: Dependency '%s' is not found", dep)
this.logger.showUser(chalk.red(`FAIL: '${dep}' is not found`))
return false
}

this.logger.debug("PASS: Dependency '%s' is found", dep)
this.logger.showUser(chalk.green(`OK: '${dep}' is found`))
}

this.logger.info("PASS: All required dependencies are found: %s", deps)
this.logger.debug("All required dependencies are found: %s", deps)

return true
}

Expand Down
116 changes: 107 additions & 9 deletions fullstack-network-manager/src/commands/cluster.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as core from '../core/index.mjs'
import {BaseCommand} from "./base.mjs";
import chalk from "chalk";

/**
* Flags for 'cluster' command
Expand All @@ -15,22 +16,94 @@ const clusterNameFlag = {
* Define the core functionalities of 'cluster' command
*/
export const ClusterCommand = class extends BaseCommand {

/**
* List available clusters
* @returns {Promise<boolean>}
*/
async getClusters() {
let cmd = `kind get clusters`

try {
let output = await this.runExec(cmd)
this.logger.showUser("\nList of available clusters \n--------------------------\n%s", output)
return true
} catch (e) {
this.logger.error("%s", e)
this.logger.showUser(e.message)
}

return false
}

/**
* Get cluster-info for the given cluster name
* @param argv arguments containing cluster name
* @returns {Promise<boolean>}
*/
async getClusterInfo(argv) {
let cmd = `kubectl cluster-info --context kind-${argv.name}`

try {
let output = await this.runExec(cmd)
this.logger.showUser(output)
return true
} catch (e) {
this.logger.error("%s", e)
this.logger.showUser(e.message)
}

return false
}

/**
* Create a cluster
* @param argv
* @returns {Promise<void>}
* @returns {Promise<boolean>}
*/
async create(argv) {
this.logger.info("creating cluster '%s'", argv.name)
let cmd = `kind create cluster -n ${argv.name} --config ${core.constants.RESOURCES_DIR}/dev-cluster.yaml`

try {
this.logger.showUser(chalk.cyan('Creating cluster:'), chalk.yellow(`${argv.name}...`))
this.logger.debug(`Invoking '${cmd}'...`)
let output = await this.runExec(cmd)
this.logger.debug(output)
this.logger.showUser(chalk.green('Created cluster:'), chalk.yellow(argv.name))

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

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

return false
}

/**
* Delete a cluster
* @param argv
* @returns {Promise<void>}
* @returns {Promise<boolean>}
*/
async delete(argv) {
this.logger.info("deleting cluster '%s'", argv.name, {name: argv.name})
let cmd = `kind delete cluster -n ${argv.name}`
try {
this.logger.debug(`Invoking '${cmd}'...`)
this.logger.showUser(chalk.cyan('Deleting cluster:'), chalk.yellow(`${argv.name}...`))
await this.runExec(cmd)
await this.getClusters()

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

return false
}

/**
Expand All @@ -40,27 +113,52 @@ export const ClusterCommand = class extends BaseCommand {
static getCommandDefinition(clusterCmd) {
return {
command: 'cluster',
desc: 'Manager FST cluster',
desc: 'Manage FST cluster',
builder: yargs => {
return yargs
.command({
command: 'create',
desc: 'Create FST cluster',
desc: 'Create a cluster',
builder: yargs => {
yargs.option('name', clusterNameFlag)
},
handler: argv => {
clusterCmd.create(argv).then()
clusterCmd.create(argv).then(r => {
if (!r) process.exit(1)
})
}
})
.command({
command: 'delete',
desc: 'Delete FST cluster',
desc: 'Delete a cluster',
builder: yargs => {
yargs.option('name', clusterNameFlag)
},
handler: argv => {
clusterCmd.delete(argv).then(r => {
if (!r) process.exit(1)
})
}
})
.command({
command: 'list',
desc: 'List all clusters',
handler: argv => {
clusterCmd.getClusters().then(r => {
if (!r) process.exit(1)
})
}
})
.command({
command: 'info',
desc: 'Get cluster info',
builder: yargs => {
yargs.option('name', clusterNameFlag)
},
handler: argv => {
clusterCmd.delete(argv).then()
clusterCmd.getClusterInfo(argv).then(r => {
if (!r) process.exit(1)
})
}
})
.demand(1, 'Select a cluster command')
Expand Down
18 changes: 15 additions & 3 deletions fullstack-network-manager/src/commands/init.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {BaseCommand} from "./base.mjs";
import * as core from "../core/index.mjs"
import chalk from "chalk";

/**
* Defines the core functionalities of 'init' command
Expand All @@ -10,11 +11,20 @@ export const InitCommand = class extends BaseCommand {
* @returns {Promise<boolean>}
*/
async init() {
return await this.checkDependencies([
let deps = [
core.constants.HELM,
core.constants.KIND,
core.constants.KUBECTL,
])
]

let status = await this.checkDependencies(deps)
if (!status) {
return false
}

this.logger.showUser(chalk.green("OK: All required dependencies are found: %s"), chalk.yellow(deps))

return status
}

/**
Expand All @@ -27,7 +37,9 @@ export const InitCommand = class extends BaseCommand {
desc: "Perform dependency checks and initialize local environment",
builder: {},
handler: (argv) => {
initCmd.init(argv)
initCmd.init(argv).then(r => {
if (!r) process.exit(1)
})
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions fullstack-network-manager/src/core/constants.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import {dirname, normalize} from "path"
import {fileURLToPath} from "url"

// directory of this fle
const CUR_FILE_DIR = dirname(fileURLToPath(import.meta.url))
const USER = `${process.env.USER}`
export const constants = {
USER: `${USER}`,
CLUSTER_NAME: `fst-${USER}`,
HELM: 'helm',
KIND: 'kind',
KUBECTL: 'kubectl',
CWD: process.cwd(),
FST_HOME_DIR: process.env.HOME + "/.fsnetman",
RESOURCES_DIR: normalize(CUR_FILE_DIR + "/../../resources")
}
Loading

0 comments on commit 78be823

Please sign in to comment.