diff --git a/cmd/mbasectl/account.go b/cmd/mbasectl/account.go new file mode 100644 index 0000000..e4a3425 --- /dev/null +++ b/cmd/mbasectl/account.go @@ -0,0 +1,90 @@ +package main + +import ( + "context" + + "mbase/pkg/client" + "mbase/pkg/mbctl" +) + +func (util *Util) CreateAccount(ctx context.Context) (*mbctl.CreateAccountResult, error) { + var err error + res := &mbctl.CreateAccountResult{} + grpcConn, cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + defer grpcConn.Close() + + params := &mbctl.CreateAccountParams{ + Username: util.username, + Password: util.password, + } + res, err = cli.CreateAccount(ctx, params) + if err != nil { + return res, err + } + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) DeleteAccount(ctx context.Context) (*mbctl.DeleteAccountResult, error) { + var err error + res := &mbctl.DeleteAccountResult{} + grpcConn, cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + defer grpcConn.Close() + + params := &mbctl.DeleteAccountParams{ + Username: util.username, + AccountID: util.accountID, + } + res, err = cli.DeleteAccount(ctx, params) + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) ListAccounts(ctx context.Context) (*mbctl.ListAccountsResult, error) { + var err error + res := &mbctl.ListAccountsResult{} + grpcConn, cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + defer grpcConn.Close() + + params := &mbctl.ListAccountsParams{} + res, err = cli.ListAccounts(ctx, params) + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) UpdateAccount(ctx context.Context) (*mbctl.UpdateAccountResult, error) { + var err error + res := &mbctl.UpdateAccountResult{} + grpcConn, cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + defer grpcConn.Close() + + params := &mbctl.UpdateAccountParams{ + Username: util.username, + AccountID: util.accountID, + NewUsername: util.newUsername, + NewPassword: util.newPassword, + } + res, err = cli.UpdateAccount(ctx, params) + if err != nil { + return res, err + } + return res, err +} diff --git a/cmd/mbasectl/dump.go b/cmd/mbasectl/dump.go new file mode 100644 index 0000000..3f9b502 --- /dev/null +++ b/cmd/mbasectl/dump.go @@ -0,0 +1,82 @@ +package main + +import ( + "bytes" + "context" + "io" + "os" + + "mbase/pkg/client" + "mbase/pkg/mbctl" +) + +func (util *Util) GetDump(ctx context.Context) (*mbctl.GetDumpResult, error) { + var err error + res := &mbctl.GetDumpResult{} + grpcConn, cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + defer grpcConn.Close() + + file := os.Stdout + if util.filename == "-" { + util.filename = "" + } + if util.filename != "" { + file, err = os.OpenFile(util.filename, os.O_CREATE|os.O_WRONLY, 0640) + if err != nil { + return res, err + } + defer file.Close() + } + + params := &mbctl.GetDumpParams{} + res, err = cli.GetDump(ctx, params) + if err != nil { + return res, err + } + + _, err = file.Write([]byte(res.Dump)) + if err != nil { + return res, err + } + + res.Dump = "" + return res, err +} + +func (util *Util) RestoreDump(ctx context.Context) (*mbctl.RestoreDumpResult, error) { + var err error + res := &mbctl.RestoreDumpResult{} + grpcConn, cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + defer grpcConn.Close() + + file := os.Stdin + if util.filename != "" { + file, err = os.Open(util.filename) + if err != nil { + return res, err + } + defer file.Close() + } + + buffer := bytes.NewBuffer(nil) + _, err = io.Copy(buffer, file) + if err != nil { + return res, err + } + + params := &mbctl.RestoreDumpParams{ + Dump: string(buffer.Bytes()), + } + res, err = cli.RestoreDump(ctx, params) + if err != nil { + return res, err + } + + return res, err +} diff --git a/cmd/mbasectl/grant.go b/cmd/mbasectl/grant.go new file mode 100644 index 0000000..4999a12 --- /dev/null +++ b/cmd/mbasectl/grant.go @@ -0,0 +1,53 @@ +package main + +import ( + "context" + + "mbase/pkg/client" + "mbase/pkg/mbctl" +) + +func (util *Util) SetGrant(ctx context.Context) (*mbctl.SetGrantResult, error) { + var err error + res := &mbctl.SetGrantResult{} + grpcConn, cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + defer grpcConn.Close() + + params := &mbctl.SetGrantParams{ + Username: util.username, + AccountID: util.accountID, + Operation: util.operation, + } + res, err = cli.SetGrant(ctx, params) + if err != nil { + return res, err + } + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) DeleteGrant(ctx context.Context) (*mbctl.DeleteGrantResult, error) { + var err error + res := &mbctl.DeleteGrantResult{} + grpcConn, cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + defer grpcConn.Close() + + params := &mbctl.DeleteGrantParams{ + Username: util.username, + AccountID: util.accountID, + Operation: util.operation, + } + res, err = cli.DeleteGrant(ctx, params) + if err != nil { + return res, err + } + return res, err +} diff --git a/cmd/mbasectl/main.go b/cmd/mbasectl/main.go new file mode 100644 index 0000000..a6da0e9 --- /dev/null +++ b/cmd/mbasectl/main.go @@ -0,0 +1,398 @@ +/* + * Copyright 2024 Oleg Borodin + */ + +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "os" + "os/user" + "path/filepath" + "time" + + "mbase/pkg/client" + "mbase/pkg/mbctl" + + "sigs.k8s.io/yaml" +) + +const ( + defaultHostname = "localhost" + rcFilename = ".certmanager.yaml" + defaultPort uint32 = client.DefaultPort + + getHelloCmd = "getHello" + helpCmd = "help" + + createAccountCmd = "createAccount" + updateAccountCmd = "updateAccount" + deleteAccountCmd = "deleteAccount" + listAccountsCmd = "listAccounts" + + setGrantCmd = "setGrant" + deleteGrantCmd = "deleteGrant" + + getDumpCmd = "getDump" + restoreDumpCmd = "restoreDump" +) + +func main() { + var err error + util := NewUtil() + err = util.Exec() + if err != nil { + os.Exit(1) + } + os.Exit(0) +} + +type Util struct { + subCmd string + cmdTimeout int64 + access client.Access + cont *mbctl.ControlClient + + caFilenamesList string + certFilename string + keyFilename string + issuerOrganizationName string + issuerOrganizationalUnitName string + issuerCommonName string + issuerID int64 + issuerName string + signerID int64 + signerName string + serviceOrganizationName string + serviceOrganizationalUnitName string + serviceCommonName string + hostnameList string + ipAdressesList string + serviceID int64 + serviceName string + encodingKey string + + accountID int64 + username string + password string + disable bool + newUsername string + newPassword string + operation string + filename string + deleteAllRecords bool +} + +func NewUtil() *Util { + var util Util + util.cmdTimeout = 120 + util.access = client.Access{ + Hostname: defaultHostname, + Port: defaultPort, + Username: "certmanager", + Password: "certmanager", + } + return &util +} + +func (util *Util) GetOpt() error { + var err error + + homeDir := os.Getenv("HOME") + if homeDir == "" { + currUsr, err := user.Current() + if err == nil { + homeDir = currUsr.HomeDir + } + } + if homeDir != "" { + confPath := filepath.Join(homeDir, rcFilename) + confData, err := os.ReadFile(confPath) + if err == nil && len(confData) > 0 { + yaml.Unmarshal(confData, &util.access) + } + } + exeName := filepath.Base(os.Args[0]) + + servicePort := int64(defaultPort) + flag.Int64Var(&util.cmdTimeout, "timeout", util.cmdTimeout, "command execution timeout") + flag.StringVar(&util.access.Hostname, "host", util.access.Hostname, "service hostname") + flag.Int64Var(&servicePort, "port", servicePort, "service port") + flag.StringVar(&util.access.Username, "user", util.access.Username, "access login") + flag.StringVar(&util.access.Password, "pass", util.access.Password, "access password") + + util.access.Port = uint32(servicePort) + + help := func() { + fmt.Println("") + fmt.Printf("Usage: %s [option] command [command option]\n", exeName) + fmt.Printf("\n") + fmt.Printf("Command list: help, %s\n", getHelloCmd) + fmt.Printf(" %s, %s, %s, %s,\n", + createAccountCmd, + deleteAccountCmd, + listAccountsCmd, + updateAccountCmd) + fmt.Printf(" %s, %s\n", + setGrantCmd, + deleteGrantCmd) + fmt.Printf(" %s, %s\n", + getDumpCmd, + restoreDumpCmd) + + fmt.Printf("\n") + fmt.Printf("Global options:\n") + flag.PrintDefaults() + fmt.Printf("\n") + } + flag.Usage = help + flag.Parse() + + args := flag.Args() + + var subCmd string + var subArgs []string + if len(args) > 0 { + subCmd = args[0] + subArgs = args[1:] + } + + switch subCmd { + case helpCmd: + help() + return errors.New("Unknown command") + case getHelloCmd: + flagSet := flag.NewFlagSet(getHelloCmd, flag.ExitOnError) + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + flagSet.Parse(subArgs) + + case createAccountCmd: + flagSet := flag.NewFlagSet(createAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.StringVar(&util.password, "password", util.password, "user password") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case deleteAccountCmd: + flagSet := flag.NewFlagSet(deleteAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case listAccountsCmd: + flagSet := flag.NewFlagSet(listAccountsCmd, flag.ExitOnError) + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case updateAccountCmd: + flagSet := flag.NewFlagSet(updateAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + + flagSet.StringVar(&util.newUsername, "newUsername", util.newUsername, "new user name") + flagSet.StringVar(&util.newPassword, "newPassword", util.newPassword, "new user password") + flagSet.BoolVar(&util.disable, "disable", util.disable, "disable account") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case setGrantCmd: + flagSet := flag.NewFlagSet(setGrantCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case deleteGrantCmd: + flagSet := flag.NewFlagSet(deleteGrantCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case getDumpCmd: + flagSet := flag.NewFlagSet(getDumpCmd, flag.ExitOnError) + flagSet.StringVar(&util.filename, "file", util.filename, "dump file name") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case restoreDumpCmd: + flagSet := flag.NewFlagSet(restoreDumpCmd, flag.ExitOnError) + flagSet.StringVar(&util.filename, "file", util.filename, "dump file name") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + default: + help() + return errors.New("Unknown command") + } + return err +} + +type Response struct { + Error bool `json:"error" yaml:"error"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` + Result any `json:"result,omitempty" yaml:"result,omitempty"` +} + +func (util *Util) Exec() error { + var err error + err = util.GetOpt() + if err != nil { + return err + } + + var timeout = time.Duration(util.cmdTimeout) * time.Second + ctx, close := context.WithTimeout(context.Background(), timeout) + defer close() + + var res any + switch util.subCmd { + case getHelloCmd: + res, err = util.GetHello(ctx) + + case createAccountCmd: + res, err = util.CreateAccount(ctx) + case updateAccountCmd: + res, err = util.UpdateAccount(ctx) + case listAccountsCmd: + res, err = util.ListAccounts(ctx) + case deleteAccountCmd: + res, err = util.DeleteAccount(ctx) + + case setGrantCmd: + res, err = util.SetGrant(ctx) + case deleteGrantCmd: + res, err = util.DeleteGrant(ctx) + + case getDumpCmd: + res, err = util.GetDump(ctx) + case restoreDumpCmd: + res, err = util.RestoreDump(ctx) + + default: + err = errors.New("Unknown cli command") + } + + var resp Response + if err != nil { + resp.Error = true + resp.Message = fmt.Sprintf("%v", err) + } else { + resp.Result = res + } + respBytes, _ := yaml.Marshal(resp) + fmt.Println(string(respBytes)) + + return err +} + +func (util *Util) GetHello(ctx context.Context) (*mbctl.GetHelloResult, error) { + var err error + res := &mbctl.GetHelloResult{} + grpcConn, cont, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + defer grpcConn.Close() + + params := &mbctl.GetHelloParams{} + res, err = cont.GetHello(ctx, params) + if err != nil { + return res, err + } + return res, err +} diff --git a/cmd/mbased/main.go b/cmd/mbased/main.go new file mode 100644 index 0000000..6c6490a --- /dev/null +++ b/cmd/mbased/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "os" + + "mbase/app/server" + "mbase/pkg/logger" +) + +func run() error { + var err error + srv, err := server.NewServer() + if err != nil { + return err + } + err = srv.Configure() + if err != nil { + return err + } + err = srv.Daemonize() + if err != nil { + return err + } + err = srv.Build() + if err != nil { + return err + } + err = srv.Run() + if err != nil { + return err + } + return err +} + +func main() { + log := logger.NewLogger("main") + err := run() + if err != nil { + log.Errorf("%v", err) + os.Exit(1) + } + os.Exit(0) +} diff --git a/cmd/mbaserestore/mainrestore.go b/cmd/mbaserestore/mainrestore.go deleted file mode 100644 index e3f738a..0000000 --- a/cmd/mbaserestore/mainrestore.go +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2022 Oleg Borodin - */ - -package main - -import ( - "bytes" - "context" - "flag" - "fmt" - "io" - "os" - "path/filepath" - "time" - - "mbase/app/config" - "mbase/app/database" - "mbase/app/descriptor" - "mbase/pkg/logger" - - "go.yaml.in/yaml/v4" -) - -func main() { - var err error - util := NewUtil() - err = util.Exec() - if err != nil { - fmt.Printf("Exec error: %s\n", err) - } -} - -type Util struct { - conf *config.Config - db *database.Database - log *logger.Logger - - filename string - deleteAllRecords bool -} - -func NewUtil() *Util { - var util Util - util.log = logger.NewLogger("logic") - return &util -} - -func (util *Util) GetOpt() error { - var err error - - exeName := filepath.Base(os.Args[0]) - - help := func() { - fmt.Println("") - fmt.Printf("Usage: %s [option]\n", exeName) - fmt.Printf("\n") - flag.PrintDefaults() - fmt.Printf("\n") - } - - flag.Usage = help - - flag.StringVar(&util.filename, "file", util.filename, "dump file name") - flag.BoolVar(&util.deleteAllRecords, "deleteAllRecords", util.deleteAllRecords, "delete all existing records before restoring") - - flag.Parse() - return err -} - -func (util *Util) Exec() error { - var err error - err = util.GetOpt() - if err != nil { - return err - } - - const timeout = 30 * time.Second - ctx, _ := context.WithTimeout(context.Background(), timeout) - - err = util.RestoreRecords(ctx) - - type ErrorDescr struct { - Error bool `json:"error,omitempty"` - Message string `json:"errorMessage,omitempty" yaml:"errorMessage,omitempty"` - } - - errDescr := ErrorDescr{} - if err != nil { - errDescr.Error = true - errDescr.Message = fmt.Sprintf("%v", err) - } - - errBytes, _ := yaml.Marshal(errDescr) - fmt.Printf("%s\n", string(errBytes)) - - return err -} - -func (util *Util) RestoreRecords(ctx context.Context) error { - var err error - - util.conf = config.NewConfig() - err = util.conf.ReadFile() - if err != nil { - return err - } - err = util.conf.ReadEnv() - if err != nil { - return err - } - - db, err := database.NewDatabase(util.conf.DataDir) - if err != nil { - return err - } - util.db = db - - err = util.db.OpenDatabase() - if err != nil { - return err - } - - file := os.Stdin - if util.filename != "" { - file, err = os.Open(util.filename) - if err != nil { - return err - } - defer file.Close() - } - - buffer := bytes.NewBuffer(nil) - _, err = io.Copy(buffer, file) - if err != nil { - return err - } - - dump := descriptor.Dump{} - - err = yaml.Unmarshal(buffer.Bytes(), &dump) - if err != nil { - return err - } - - if util.deleteAllRecords { - err = util.db.CleanDatabase(ctx) - if err != nil { - return err - } - } - - for _, account := range dump.Accounts { - util.log.Infof("Insert account %s", account.Username) - err = util.db.InsertAccount(ctx, &account) - if err != nil { - util.log.Errorf("Insert account error: %v", err) - } - } - for _, grant := range dump.Grants { - util.log.Infof("Insert grant %s for account %d", grant.Operation, grant.AccountID) - err = util.db.InsertGrant(ctx, &grant) - if err != nil { - util.log.Errorf("Insert account error: %v", err) - } - } - - return err -}