moonstream/nodes/node_balancer/cmd/nodebalancer/cli.go

373 wiersze
11 KiB
Go

2022-07-11 14:01:10 +00:00
package main
2022-03-16 14:49:39 +00:00
import (
2022-05-16 19:54:22 +00:00
"encoding/json"
2022-03-16 14:49:39 +00:00
"flag"
"fmt"
"log"
2022-03-16 14:49:39 +00:00
"os"
2022-05-10 18:25:04 +00:00
"strings"
2022-03-16 14:49:39 +00:00
2022-05-16 19:54:22 +00:00
bugout "github.com/bugout-dev/bugout-go/pkg"
"github.com/google/uuid"
2022-03-16 14:49:39 +00:00
)
var (
// Storing CLI definitions at server startup
2022-03-16 14:49:39 +00:00
stateCLI StateCLI
2022-03-21 20:36:12 +00:00
bugoutClient bugout.BugoutClient
2022-03-16 14:49:39 +00:00
)
2022-05-10 18:25:04 +00:00
type flagSlice []string
func (i *flagSlice) String() string {
return strings.Join(*i, ", ")
}
func (i *flagSlice) Set(value string) error {
*i = append(*i, value)
return nil
}
2022-03-16 14:49:39 +00:00
// Command Line Interface state
type StateCLI struct {
2022-07-11 13:53:03 +00:00
addAccessCmd *flag.FlagSet
generateConfigCmd *flag.FlagSet
deleteAccessCmd *flag.FlagSet
serverCmd *flag.FlagSet
usersCmd *flag.FlagSet
versionCmd *flag.FlagSet
2022-03-16 14:49:39 +00:00
// Common flags
2022-05-10 18:25:04 +00:00
configPathFlag string
2022-05-16 19:54:22 +00:00
helpFlag bool
2022-03-16 14:49:39 +00:00
// Add user access flags
userIDFlag string
accessIDFlag string
accessNameFlag string
accessDescriptionFlag string
blockchainAccessFlag bool
extendedMethodsFlag bool
2022-03-16 14:49:39 +00:00
// Server flags
listeningAddrFlag string
listeningPortFlag string
2022-03-17 11:28:19 +00:00
enableHealthCheckFlag bool
enableDebugFlag bool
2022-03-17 17:35:53 +00:00
// Users list flags
limitFlag int
offsetFlag int
2022-03-17 11:28:19 +00:00
}
func (s *StateCLI) usage() {
2022-07-11 13:53:03 +00:00
fmt.Printf(`usage: nodebalancer [-h] {%[1]s,%[2]s,%[3]s,%[4]s,%[5]s,%[6]s} ...
2022-03-17 11:28:19 +00:00
Moonstream node balancer CLI
optional arguments:
-h, --help show this help message and exit
2022-03-17 11:28:19 +00:00
subcommands:
2022-07-11 13:53:03 +00:00
{%[1]s,%[2]s,%[3]s,%[4]s,%[5]s,%[6]s}
`, s.addAccessCmd.Name(), s.generateConfigCmd.Name(), s.deleteAccessCmd.Name(), s.serverCmd.Name(), s.usersCmd.Name(), s.versionCmd.Name())
2022-03-17 11:28:19 +00:00
}
// Check if required flags are set
2022-03-17 11:28:19 +00:00
func (s *StateCLI) checkRequirements() {
if s.helpFlag {
switch {
case s.addAccessCmd.Parsed():
2022-03-17 17:35:53 +00:00
fmt.Printf("Add new user access token\n\n")
s.addAccessCmd.PrintDefaults()
os.Exit(0)
2022-07-11 13:53:03 +00:00
case s.generateConfigCmd.Parsed():
fmt.Printf("Generate new configuration\n\n")
s.generateConfigCmd.PrintDefaults()
os.Exit(0)
case s.deleteAccessCmd.Parsed():
2022-03-17 17:35:53 +00:00
fmt.Printf("Delete user access token\n\n")
s.deleteAccessCmd.PrintDefaults()
os.Exit(0)
2022-03-17 11:28:19 +00:00
case s.serverCmd.Parsed():
2022-03-17 17:35:53 +00:00
fmt.Printf("Start nodebalancer server\n\n")
2022-03-17 11:28:19 +00:00
s.serverCmd.PrintDefaults()
os.Exit(0)
2022-03-17 11:28:19 +00:00
case s.usersCmd.Parsed():
2022-03-17 17:35:53 +00:00
fmt.Printf("List user access tokens\n\n")
2022-03-17 11:28:19 +00:00
s.usersCmd.PrintDefaults()
os.Exit(0)
2022-03-17 11:28:19 +00:00
case s.versionCmd.Parsed():
2022-03-17 17:35:53 +00:00
fmt.Printf("Show version\n\n")
2022-03-17 11:28:19 +00:00
s.versionCmd.PrintDefaults()
os.Exit(0)
2022-03-17 11:28:19 +00:00
default:
s.usage()
os.Exit(0)
}
}
switch {
case s.addAccessCmd.Parsed():
if s.userIDFlag == "" {
2022-03-17 17:35:53 +00:00
fmt.Printf("User ID should be specified\n\n")
s.addAccessCmd.PrintDefaults()
os.Exit(1)
}
if s.accessIDFlag == "" {
s.accessIDFlag = uuid.New().String()
}
if s.accessNameFlag == "" {
2022-03-17 17:35:53 +00:00
fmt.Printf("Access name should be specified\n\n")
s.addAccessCmd.PrintDefaults()
os.Exit(1)
}
case s.deleteAccessCmd.Parsed():
if s.userIDFlag == "" && s.accessIDFlag == "" {
2022-03-17 17:35:53 +00:00
fmt.Printf("User or access ID flag should be specified\n\n")
s.deleteAccessCmd.PrintDefaults()
os.Exit(1)
2022-03-17 11:28:19 +00:00
}
2022-03-17 17:35:53 +00:00
case s.usersCmd.Parsed():
if s.offsetFlag < 0 || s.limitFlag < 0 {
fmt.Printf("Offset and limit flags should be greater then zero\n\n")
s.usersCmd.PrintDefaults()
os.Exit(1)
}
}
2022-05-10 18:25:04 +00:00
// Load configuration
config, err := GetConfigPath(s.configPathFlag)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if !config.ConfigExists {
if err := GenerateDefaultConfig(config); err != nil {
fmt.Println(err)
os.Exit(1)
}
} else {
log.Printf("Loaded configuration from %s", config.ConfigPath)
2022-03-17 11:28:19 +00:00
}
2022-07-11 13:53:03 +00:00
s.configPathFlag = config.ConfigPath
2022-03-16 14:49:39 +00:00
}
func (s *StateCLI) populateCLI() {
// Subcommands setup
s.addAccessCmd = flag.NewFlagSet("add-access", flag.ExitOnError)
2022-07-11 13:53:03 +00:00
s.generateConfigCmd = flag.NewFlagSet("generate-config", flag.ExitOnError)
s.deleteAccessCmd = flag.NewFlagSet("delete-access", flag.ExitOnError)
2022-03-16 14:49:39 +00:00
s.serverCmd = flag.NewFlagSet("server", flag.ExitOnError)
s.usersCmd = flag.NewFlagSet("users", flag.ExitOnError)
2022-03-17 11:28:19 +00:00
s.versionCmd = flag.NewFlagSet("version", flag.ExitOnError)
2022-03-16 14:49:39 +00:00
2022-03-17 11:28:19 +00:00
// Common flag pointers
2022-07-11 13:53:03 +00:00
for _, fs := range []*flag.FlagSet{s.addAccessCmd, s.generateConfigCmd, s.deleteAccessCmd, s.serverCmd, s.usersCmd, s.versionCmd} {
2022-03-17 11:28:19 +00:00
fs.BoolVar(&s.helpFlag, "help", false, "Show help message")
fs.StringVar(&s.configPathFlag, "config", "", "Path to configuration file (default: ~/.nodebalancer/config.json)")
2022-03-17 11:28:19 +00:00
}
// Add, delete and list user access subcommand flag pointers
for _, fs := range []*flag.FlagSet{s.addAccessCmd, s.deleteAccessCmd, s.usersCmd} {
fs.StringVar(&s.userIDFlag, "user-id", "", "Bugout user ID")
fs.StringVar(&s.accessIDFlag, "access-id", "", "UUID for access identification")
}
// Add user access subcommand flag pointers
s.addAccessCmd.StringVar(&s.accessNameFlag, "name", "", "Name of access")
s.addAccessCmd.StringVar(&s.accessDescriptionFlag, "description", "", "Description of access")
s.addAccessCmd.BoolVar(&s.blockchainAccessFlag, "blockchain-access", false, "Provide if allow direct access to blockchain nodes")
s.addAccessCmd.BoolVar(&s.extendedMethodsFlag, "extended-methods", false, "Provide to be able to execute not whitelisted methods")
2022-03-17 11:28:19 +00:00
// Server subcommand flag pointers
s.serverCmd.StringVar(&s.listeningAddrFlag, "host", "127.0.0.1", "Server listening address")
s.serverCmd.StringVar(&s.listeningPortFlag, "port", "8544", "Server listening port")
s.serverCmd.BoolVar(&s.enableHealthCheckFlag, "healthcheck", false, "To enable healthcheck set healthcheck flag")
2022-03-17 11:28:19 +00:00
s.serverCmd.BoolVar(&s.enableDebugFlag, "debug", false, "To enable debug mode with extended log set debug flag")
2022-03-17 17:35:53 +00:00
// Users list subcommand flag pointers
s.usersCmd.IntVar(&s.limitFlag, "limit", 10, "Output result limit")
s.usersCmd.IntVar(&s.offsetFlag, "offset", 0, "Result output offset")
2022-03-16 14:49:39 +00:00
}
func cli() {
2022-03-16 14:49:39 +00:00
stateCLI.populateCLI()
if len(os.Args) < 2 {
2022-03-17 11:28:19 +00:00
stateCLI.usage()
2022-03-16 14:49:39 +00:00
os.Exit(1)
}
// Init bugout client
bc, err := bugout.ClientFromEnv()
if err != nil {
fmt.Printf("Unable to initialize bugout client, err: %v\n", err)
os.Exit(1)
}
bugoutClient = bc
2022-03-16 14:49:39 +00:00
// Parse subcommands and appropriate FlagSet
switch os.Args[1] {
case "add-access":
stateCLI.addAccessCmd.Parse(os.Args[2:])
stateCLI.checkRequirements()
2022-05-17 13:30:28 +00:00
proposedUserAccess := ClientResourceData{
UserID: stateCLI.userIDFlag,
AccessID: stateCLI.accessIDFlag,
Name: stateCLI.accessNameFlag,
Description: stateCLI.accessDescriptionFlag,
BlockchainAccess: stateCLI.blockchainAccessFlag,
ExtendedMethods: stateCLI.extendedMethodsFlag,
}
2022-03-21 20:36:12 +00:00
_, err := bugoutClient.Brood.FindUser(
NB_CONTROLLER_TOKEN,
2022-03-21 20:36:12 +00:00
map[string]string{
"user_id": proposedUserAccess.UserID,
"application_id": NB_APPLICATION_ID,
2022-03-21 20:36:12 +00:00
},
)
if err != nil {
fmt.Printf("User does not exists, err: %v\n", err)
2022-03-21 20:36:12 +00:00
os.Exit(1)
}
resource, err := bugoutClient.Brood.CreateResource(NB_CONTROLLER_TOKEN, NB_APPLICATION_ID, proposedUserAccess)
if err != nil {
fmt.Printf("Unable to create user access, err: %v\n", err)
os.Exit(1)
}
2022-03-21 20:36:12 +00:00
resource_data, err := json.Marshal(resource.ResourceData)
if err != nil {
fmt.Printf("Unable to encode resource %s data interface to json, err: %v", resource.Id, err)
os.Exit(1)
}
2022-03-21 20:36:12 +00:00
fmt.Println(string(resource_data))
2022-07-11 13:53:03 +00:00
case "generate-config":
stateCLI.generateConfigCmd.Parse(os.Args[2:])
stateCLI.checkRequirements()
case "delete-access":
stateCLI.deleteAccessCmd.Parse(os.Args[2:])
stateCLI.checkRequirements()
2022-03-21 20:36:12 +00:00
queryParameters := make(map[string]string)
if stateCLI.userIDFlag != "" {
queryParameters["user_id"] = stateCLI.userIDFlag
}
if stateCLI.accessIDFlag != "" {
queryParameters["access_id"] = stateCLI.accessIDFlag
}
resources, err := bugoutClient.Brood.GetResources(
NB_CONTROLLER_TOKEN,
NB_APPLICATION_ID,
2022-03-21 20:36:12 +00:00
queryParameters,
)
if err != nil {
fmt.Printf("Unable to get Bugout resources, err: %v\n", err)
os.Exit(1)
}
2022-05-17 13:30:28 +00:00
var userAccesses []ClientResourceData
for _, resource := range resources.Resources {
deletedResource, err := bugoutClient.Brood.DeleteResource(NB_CONTROLLER_TOKEN, resource.Id)
2022-03-21 20:36:12 +00:00
if err != nil {
fmt.Printf("Unable to delete resource %s, err: %v\n", resource.Id, err)
2022-03-21 20:36:12 +00:00
continue
}
resource_data, err := json.Marshal(deletedResource.ResourceData)
if err != nil {
fmt.Printf("Unable to encode resource %s data interface to json, err: %v\n", resource.Id, err)
2022-03-21 20:36:12 +00:00
continue
}
2022-05-17 13:30:28 +00:00
var userAccess ClientResourceData
2022-03-21 20:36:12 +00:00
err = json.Unmarshal(resource_data, &userAccess)
if err != nil {
fmt.Printf("Unable to decode resource %s data json to structure, err: %v\n", resource.Id, err)
continue
}
2022-03-21 20:36:12 +00:00
userAccesses = append(userAccesses, userAccess)
}
userAccessesJson, err := json.Marshal(userAccesses)
if err != nil {
fmt.Printf("Unable to marshal user access struct, err: %v\n", err)
os.Exit(1)
}
fmt.Println(string(userAccessesJson))
2022-03-16 14:49:39 +00:00
case "server":
stateCLI.serverCmd.Parse(os.Args[2:])
2022-03-17 11:28:19 +00:00
stateCLI.checkRequirements()
CheckEnvVarSet()
2022-03-16 14:49:39 +00:00
Server()
2022-03-17 11:58:23 +00:00
case "users":
stateCLI.usersCmd.Parse(os.Args[2:])
2022-03-17 11:28:19 +00:00
stateCLI.checkRequirements()
2022-03-21 20:36:12 +00:00
var queryParameters map[string]string
if stateCLI.userIDFlag != "" {
queryParameters["user_id"] = stateCLI.userIDFlag
}
if stateCLI.accessIDFlag != "" {
queryParameters["access_id"] = stateCLI.accessIDFlag
}
resources, err := bugoutClient.Brood.GetResources(
NB_CONTROLLER_TOKEN,
NB_APPLICATION_ID,
2022-03-21 20:36:12 +00:00
queryParameters,
)
2022-03-16 14:49:39 +00:00
if err != nil {
fmt.Printf("Unable to get Bugout resources, err: %v\n", err)
os.Exit(1)
}
2022-05-17 13:30:28 +00:00
var userAccesses []ClientResourceData
2022-03-17 17:35:53 +00:00
offset := stateCLI.offsetFlag
if stateCLI.offsetFlag > len(resources.Resources) {
offset = len(resources.Resources)
}
limit := stateCLI.offsetFlag + stateCLI.limitFlag
if limit > len(resources.Resources) {
limit = len(resources.Resources[offset:]) + offset
}
2022-03-21 20:36:12 +00:00
for _, resource := range resources.Resources[offset:limit] {
resource_data, err := json.Marshal(resource.ResourceData)
if err != nil {
fmt.Printf("Unable to encode resource %s data interface to json, err: %v\n", resource.Id, err)
2022-03-21 20:36:12 +00:00
continue
}
2022-05-17 13:30:28 +00:00
var userAccess ClientResourceData
2022-03-21 20:36:12 +00:00
err = json.Unmarshal(resource_data, &userAccess)
if err != nil {
fmt.Printf("Unable to decode resource %s data json to structure, err: %v\n", resource.Id, err)
2022-03-21 20:36:12 +00:00
continue
}
userAccesses = append(userAccesses, userAccess)
2022-03-16 14:49:39 +00:00
}
userAccessesJson, err := json.Marshal(userAccesses)
2022-03-16 14:49:39 +00:00
if err != nil {
fmt.Printf("Unable to marshal user accesses struct, err: %v\n", err)
os.Exit(1)
2022-03-16 14:49:39 +00:00
}
fmt.Println(string(userAccessesJson))
2022-03-17 11:58:23 +00:00
2022-03-16 14:49:39 +00:00
case "version":
2022-03-17 11:28:19 +00:00
stateCLI.versionCmd.Parse(os.Args[2:])
stateCLI.checkRequirements()
fmt.Printf("v%s\n", NB_VERSION)
2022-03-17 11:58:23 +00:00
2022-03-16 14:49:39 +00:00
default:
2022-03-17 11:28:19 +00:00
stateCLI.usage()
2022-03-16 14:49:39 +00:00
os.Exit(1)
}
}