diff --git a/cmd/mbasectl/accountcmd/acccmd.go b/cmd/mbasectl/accountcmd/acccmd.go new file mode 100644 index 0000000..82dace9 --- /dev/null +++ b/cmd/mbasectl/accountcmd/acccmd.go @@ -0,0 +1,110 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +const ( + uuidRegex = `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$` + defaultHostname = "localhost:1025" +) + +func NewAccountUtil() *AccountUtil { + return &AccountUtil{} +} + +type AccountUtil struct { + createAccountParams CreateAccountParams + updateAccountParams UpdateAccountParams + getAccountParams GetAccountParams + deleteAccountParams DeleteAccountParams + listAccountsParams ListAccountsParams + commonAccountParams CommonAccountParams +} + +type CommonAccountParams struct { + Username string + Password string + Hostname string + Timeout uint64 + SkipTLSVerify bool +} + +func (util *AccountUtil) MakeAccountCmds() *cobra.Command { + var subCmd = &cobra.Command{ + Use: "accounts", + Short: "Account operations", + Aliases: []string{"account"}, + } + const defaultTimeout uint64 = 10 + + subCmd.PersistentFlags().StringVarP(&util.commonAccountParams.Username, "user", "U", util.commonAccountParams.Username, "Username") + subCmd.PersistentFlags().StringVarP(&util.commonAccountParams.Password, "pass", "P", util.commonAccountParams.Password, "Password") + subCmd.PersistentFlags().StringVarP(&util.commonAccountParams.Hostname, "host", "X", defaultHostname, "Hostname") + subCmd.PersistentFlags().Uint64VarP(&util.commonAccountParams.Timeout, "timeout", "T", defaultTimeout, "Operation timeout") + subCmd.PersistentFlags().BoolVarP(&util.commonAccountParams.SkipTLSVerify, "skipVerify", "S", true, "Skip server certificate verify") + subCmd.MarkFlagsRequiredTogether("user", "pass") + + vi := viper.New() + vi.SetEnvPrefix("mbase") + vi.BindEnv("user") + vi.BindEnv("pass") + util.commonAccountParams.Username = vi.GetString("user") + util.commonAccountParams.Password = vi.GetString("pass") + + // CreateAccount + var createAccountCmd = &cobra.Command{ + Use: "create [user:pass@]hostname[:port] username password", + Short: "Create user account", + Args: cobra.ExactArgs(3), + Run: util.CreateAccount, + } + subCmd.AddCommand(createAccountCmd) + + // GetAccount + var getAccountCmd = &cobra.Command{ + Use: "get [user:pass@]hostname[:port] accountId|username", + Short: "Get account info", + Args: cobra.ExactArgs(2), + Run: util.GetAccount, + } + subCmd.AddCommand(getAccountCmd) + + // UpdateAccount + var updateAccountCmd = &cobra.Command{ + Use: "update [user:pass@]hostname[:port] username|accounId", + Short: "Update account parameters", + Args: cobra.ExactArgs(2), + Run: util.UpdateAccount, + } + updateAccountCmd.Flags().StringVarP(&util.updateAccountParams.NewUsername, "newname", "u", "", "New username") + updateAccountCmd.Flags().StringVarP(&util.updateAccountParams.NewPassword, "newpass", "p", "", "New password") + updateAccountCmd.MarkFlagsOneRequired("newname", "newpass") + subCmd.AddCommand(updateAccountCmd) + + // DeleteAccount + var deleteAccountCmd = &cobra.Command{ + Use: "delete [user:pass@]hostname[:port] username|accountId", + Short: "Delete account", + Args: cobra.ExactArgs(2), + Run: util.DeleteAccount, + } + subCmd.AddCommand(deleteAccountCmd) + + // ListAccount + var listAccountsCmd = &cobra.Command{ + Use: "list [user:pass@]hostname[:port]", + Short: "list accounts", + Args: cobra.ExactArgs(1), + Run: util.ListAccounts, + } + listAccountsCmd.Flags().BoolVarP(&util.listAccountsParams.Detail, "detail", "d", false, "Show detail information") + listAccountsCmd.Flags().StringVarP(&util.listAccountsParams.Regex, "regex", "r", "", "Output regexp for usernames") + subCmd.AddCommand(listAccountsCmd) + + return subCmd +} diff --git a/cmd/mbasectl/accountcmd/createacc.go b/cmd/mbasectl/accountcmd/createacc.go new file mode 100644 index 0000000..524934f --- /dev/null +++ b/cmd/mbasectl/accountcmd/createacc.go @@ -0,0 +1,68 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "context" + "time" + + "github.com/spf13/cobra" + + "mbase/pkg/accntcli" + "mbase/pkg/terms" +) + +// CreateAccount +type CreateAccountParams struct { + NewUsername string + NewPassword string +} +type CreateAccountResult struct { + AccountID string `json:"accountId"` + Grants map[string]string `json:"grantsIds,omitempty"` +} + +func (util *AccountUtil) CreateAccount(cmd *cobra.Command, args []string) { + util.commonAccountParams.Hostname = args[0] + util.createAccountParams.NewUsername = args[1] + util.createAccountParams.NewPassword = args[2] + res, err := util.createAccount(&util.commonAccountParams, &util.createAccountParams) + printResponse(res, err) +} + +func (util *AccountUtil) createAccount(common *CommonAccountParams, params *CreateAccountParams) (*CreateAccountResult, error) { + var err error + res := &CreateAccountResult{ + Grants: make(map[string]string, 0), + } + + timeout := time.Duration(common.Timeout) * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + ref, err := accntcli.ParseHostinfo(common.Hostname) + if err != nil { + return res, err + } + ref.SetUserinfo(common.Username, common.Password) + mw := accntcli.NewBasicAuthMiddleware(ref.Userinfo()) + cli := accntcli.NewClient(nil, mw) + + accountID, err := cli.CreateAccount(ctx, ref.Host(), params.NewUsername, params.NewPassword) + if err != nil { + return res, err + } + + fullRights := []string{ + terms.RightWriteAccounts, + terms.RightReadAccounts, + } + for _, right := range fullRights { + id, err := cli.CreateGrantByAccountID(ctx, ref.Host(), accountID, right, ".*") + if err != nil { + return res, err + } + res.Grants[id] = right + } + res.AccountID = accountID + return res, err +} diff --git a/cmd/mbasectl/accountcmd/creategrant.go b/cmd/mbasectl/accountcmd/creategrant.go new file mode 100644 index 0000000..2d54dd3 --- /dev/null +++ b/cmd/mbasectl/accountcmd/creategrant.go @@ -0,0 +1,63 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "context" + "regexp" + "strings" + "time" + + "github.com/spf13/cobra" + + "mbase/pkg/accntcli" +) + +// CreateGrant +type CreateGrantParams struct { + AccountID string + Right string + Pattern string +} +type CreateGrantResult struct { + GrantID string `json:"grantId"` +} + +func (util *GrantUtil) CreateGrant(cmd *cobra.Command, args []string) { + util.commonGrantParams.Hostname = args[0] + util.createGrantParams.AccountID = args[1] + util.createGrantParams.Right = args[2] + util.createGrantParams.Pattern = args[3] + res, err := util.createGrant(&util.commonGrantParams, &util.createGrantParams) + printResponse(res, err) +} + +func (util *GrantUtil) createGrant(common *CommonGrantParams, params *CreateGrantParams) (*CreateGrantResult, error) { + var err error + res := &CreateGrantResult{} + + timeout := time.Duration(common.Timeout) * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + ref, err := accntcli.ParseHostinfo(common.Hostname) + if err != nil { + return res, err + } + ref.SetUserinfo(common.Username, common.Password) + mw := accntcli.NewBasicAuthMiddleware(ref.Userinfo()) + cli := accntcli.NewClient(nil, mw) + + re := regexp.MustCompile(uuidRegex) + id := strings.ToLower(params.AccountID) + var opres string + if re.MatchString(id) { + opres, err = cli.CreateGrantByAccountID(ctx, ref.Host(), id, params.Right, params.Pattern) + } else { + opres, err = cli.CreateGrantByUsername(ctx, ref.Host(), params.AccountID, params.Right, params.Pattern) + } + if err != nil { + return res, err + } + res.GrantID = opres + return res, err +} diff --git a/cmd/mbasectl/accountcmd/delacc.go b/cmd/mbasectl/accountcmd/delacc.go new file mode 100644 index 0000000..7f7fc48 --- /dev/null +++ b/cmd/mbasectl/accountcmd/delacc.go @@ -0,0 +1,56 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "context" + "regexp" + "strings" + "time" + + "github.com/spf13/cobra" + + "mbase/pkg/accntcli" +) + +// DeleteAccount +type DeleteAccountParams struct { + AccountID string + Timeout uint64 +} + +type DeleteAccountResult struct{} + +func (util *AccountUtil) DeleteAccount(cmd *cobra.Command, args []string) { + util.commonAccountParams.Hostname = args[0] + util.deleteAccountParams.AccountID = args[1] + res, err := util.deleteAccount(&util.commonAccountParams, &util.deleteAccountParams) + printResponse(res, err) +} +func (util *AccountUtil) deleteAccount(common *CommonAccountParams, params *DeleteAccountParams) (*DeleteAccountResult, error) { + var err error + res := &DeleteAccountResult{} + + timeout := time.Duration(common.Timeout) * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + ref, err := accntcli.ParseHostinfo(common.Hostname) + if err != nil { + return res, err + } + ref.SetUserinfo(common.Username, common.Password) + mw := accntcli.NewBasicAuthMiddleware(ref.Userinfo()) + cli := accntcli.NewClient(nil, mw) + + re := regexp.MustCompile(uuidRegex) + id := strings.ToLower(params.AccountID) + if re.MatchString(id) { + err = cli.DeleteAccountByID(ctx, ref.Host(), id) + } else { + err = cli.DeleteAccountByName(ctx, ref.Host(), params.AccountID) + } + if err != nil { + return res, err + } + return res, err +} diff --git a/cmd/mbasectl/accountcmd/delgrant.go b/cmd/mbasectl/accountcmd/delgrant.go new file mode 100644 index 0000000..0f0098d --- /dev/null +++ b/cmd/mbasectl/accountcmd/delgrant.go @@ -0,0 +1,49 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "context" + "strings" + "time" + + "github.com/spf13/cobra" + + "mbase/pkg/accntcli" +) + +// DeleteGrant +type DeleteGrantParams struct { + GrantID string +} + +type DeleteGrantResult struct{} + +func (util *GrantUtil) DeleteGrant(cmd *cobra.Command, args []string) { + util.commonGrantParams.Hostname = args[0] + util.deleteGrantParams.GrantID = args[1] + res, err := util.deleteGrant(&util.commonGrantParams, &util.deleteGrantParams) + printResponse(res, err) +} +func (util *GrantUtil) deleteGrant(common *CommonGrantParams, params *DeleteGrantParams) (*DeleteGrantResult, error) { + var err error + res := &DeleteGrantResult{} + + timeout := time.Duration(common.Timeout) * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + ref, err := accntcli.ParseHostinfo(common.Hostname) + if err != nil { + return res, err + } + ref.SetUserinfo(common.Username, common.Password) + mw := accntcli.NewBasicAuthMiddleware(ref.Userinfo()) + cli := accntcli.NewClient(nil, mw) + + id := strings.ToLower(params.GrantID) + err = cli.DeleteGrant(ctx, ref.Host(), id) + if err != nil { + return res, err + } + return res, err +} diff --git a/cmd/mbasectl/accountcmd/getacc.go b/cmd/mbasectl/accountcmd/getacc.go new file mode 100644 index 0000000..258bae9 --- /dev/null +++ b/cmd/mbasectl/accountcmd/getacc.go @@ -0,0 +1,61 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "context" + "regexp" + "strings" + "time" + + "github.com/spf13/cobra" + + "mbase/pkg/accntcli" + "mbase/pkg/descr" +) + +// GetAccount +type GetAccountParams struct { + Timeout uint64 + AccountID string +} + +func (util *AccountUtil) GetAccount(cmd *cobra.Command, args []string) { + util.commonAccountParams.Hostname = args[0] + util.getAccountParams.AccountID = args[1] + res, err := util.getAccount(&util.commonAccountParams, &util.getAccountParams) + printResponse(res, err) +} + +type GetAccountResult struct { + Account *descr.AccountShort `json:"account,omitempty"` +} + +func (util *AccountUtil) getAccount(common *CommonAccountParams, params *GetAccountParams) (*GetAccountResult, error) { + var err error + res := &GetAccountResult{} + opres := &descr.AccountShort{} + re := regexp.MustCompile(uuidRegex) + id := strings.ToLower(params.AccountID) + + timeout := time.Duration(common.Timeout) * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + ref, err := accntcli.ParseHostinfo(common.Hostname) + if err != nil { + return res, err + } + ref.SetUserinfo(common.Username, common.Password) + mw := accntcli.NewBasicAuthMiddleware(ref.Userinfo()) + cli := accntcli.NewClient(nil, mw) + if re.MatchString(id) { + opres, err = cli.GetAccountByID(ctx, ref.Host(), id) + } else { + opres, err = cli.GetAccountByName(ctx, ref.Host(), params.AccountID) + } + if err != nil { + return res, err + } + res.Account = opres + return res, err +} diff --git a/cmd/mbasectl/accountcmd/getgrant.go b/cmd/mbasectl/accountcmd/getgrant.go new file mode 100644 index 0000000..bf4d7b4 --- /dev/null +++ b/cmd/mbasectl/accountcmd/getgrant.go @@ -0,0 +1,56 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "context" + "strings" + "time" + + "github.com/spf13/cobra" + + "mbase/pkg/accntcli" + "mbase/pkg/descr" +) + +// GetGrant +type GetGrantParams struct { + GrantID string +} + +type GetGrantResult struct { + Grant *descr.Grant `json:"grant,omitempty"` +} + +func (util *GrantUtil) GetGrant(cmd *cobra.Command, args []string) { + util.commonGrantParams.Hostname = args[0] + util.getGrantParams.GrantID = args[1] + + res, err := util.getGrant(&util.commonGrantParams, &util.getGrantParams) + printResponse(res, err) +} + +func (util *GrantUtil) getGrant(common *CommonGrantParams, params *GetGrantParams) (*GetGrantResult, error) { + var err error + res := &GetGrantResult{} + opres := &descr.Grant{} + + timeout := time.Duration(common.Timeout) * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + ref, err := accntcli.ParseHostinfo(common.Hostname) + if err != nil { + return res, err + } + ref.SetUserinfo(common.Username, common.Password) + mw := accntcli.NewBasicAuthMiddleware(ref.Userinfo()) + cli := accntcli.NewClient(nil, mw) + + id := strings.ToLower(params.GrantID) + opres, err = cli.GetGrant(ctx, ref.Host(), id) + if err != nil { + return res, err + } + res.Grant = opres + return res, err +} diff --git a/cmd/mbasectl/accountcmd/grantcmd.go b/cmd/mbasectl/accountcmd/grantcmd.go new file mode 100644 index 0000000..a259bd9 --- /dev/null +++ b/cmd/mbasectl/accountcmd/grantcmd.go @@ -0,0 +1,101 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +type GrantUtil struct { + createGrantParams CreateGrantParams + updateGrantParams UpdateGrantParams + getGrantParams GetGrantParams + deleteGrantParams DeleteGrantParams + listGrantsParams ListGrantsParams + commonGrantParams CommonGrantParams +} + +func NewGrantUtil() *GrantUtil { + return &GrantUtil{} +} + +func (util *GrantUtil) MakeGrantCmds() *cobra.Command { + var subCmd = &cobra.Command{ + Use: "grants", + Short: "Grant operations", + Aliases: []string{"grant"}, + } + const defaultTimeout uint64 = 10 + + subCmd.PersistentFlags().StringVarP(&util.commonGrantParams.Username, "user", "u", "", "Username") + subCmd.PersistentFlags().StringVarP(&util.commonGrantParams.Password, "pass", "p", "", "Password") + subCmd.PersistentFlags().Uint64VarP(&util.commonGrantParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout") + subCmd.PersistentFlags().BoolVarP(&util.commonGrantParams.SkipTLSVerify, "skipVerify", "S", true, "Skip server certificate verify") + + vi := viper.New() + vi.SetEnvPrefix("mbase") + vi.BindEnv("user") + vi.BindEnv("pass") + util.commonGrantParams.Username = vi.GetString("user") + util.commonGrantParams.Password = vi.GetString("pass") + + // CreateGrant + var createGrantCmd = &cobra.Command{ + Use: "create [user:pass@]hostname[:port] username|accountId rigth pattern", + Short: "Create grant", + Args: cobra.ExactArgs(4), + Run: util.CreateGrant, + } + subCmd.AddCommand(createGrantCmd) + + // GetGrant + var getGrantCmd = &cobra.Command{ + Use: "get [user:pass@]hostname[:port] grantId", + Short: "Get detail grant info", + Args: cobra.ExactArgs(2), + Run: util.GetGrant, + } + subCmd.AddCommand(getGrantCmd) + + // UpdateGrant + var updateGrantCmd = &cobra.Command{ + Use: "update [user:pass@]hostname[:port] gruntId newPattern", + Short: "Update grant parameters", + Args: cobra.ExactArgs(3), + Run: util.UpdateGrant, + } + subCmd.AddCommand(updateGrantCmd) + + // DeleteGrant + var deleteGrantCmd = &cobra.Command{ + Use: "delete [user:pass@]hostname[:port] gruntId ", + Short: "Delete grant", + Args: cobra.ExactArgs(2), + + Run: util.DeleteGrant, + } + subCmd.AddCommand(deleteGrantCmd) + + // ListGrants + var listGrantsCmd = &cobra.Command{ + Use: "list [user:pass@]hostname[:port] accountId|username", + Short: "list user grants", + Args: cobra.ExactArgs(2), + Run: util.ListGrants, + } + listGrantsCmd.Flags().BoolVarP(&util.listGrantsParams.Detail, "detail", "d", false, "Show detail information") + + subCmd.AddCommand(listGrantsCmd) + + return subCmd +} + +type CommonGrantParams struct { + Username string + Password string + Hostname string + Timeout uint64 + SkipTLSVerify bool +} diff --git a/cmd/mbasectl/accountcmd/listacc.go b/cmd/mbasectl/accountcmd/listacc.go new file mode 100644 index 0000000..1dd0a9d --- /dev/null +++ b/cmd/mbasectl/accountcmd/listacc.go @@ -0,0 +1,90 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "context" + "regexp" + "time" + + "github.com/spf13/cobra" + + "mbase/pkg/accntcli" + "mbase/pkg/descr" +) + +// ListAccounts +type ListAccountsParams struct { + Timeout uint64 + Detail bool + Regex string +} + +type Userinfo struct { + Username string `json:"username,omitempty"` + AccountID string `json:"accountId,omitempty"` + Rights map[string]string `json:"rights,omitempty"` +} + +type ListAccountsResult struct { + Accounts []descr.AccountShort `json:"accounts,omitempty"` + Users []Userinfo `json:"users,omitempty"` +} + +func (util *AccountUtil) ListAccounts(cmd *cobra.Command, args []string) { + util.commonAccountParams.Hostname = args[0] + res, err := util.listAccounts(&util.commonAccountParams, &util.listAccountsParams) + printResponse(res, err) +} +func (util *AccountUtil) listAccounts(common *CommonAccountParams, params *ListAccountsParams) (*ListAccountsResult, error) { + var err error + res := &ListAccountsResult{} + + outregex, err := regexp.Compile(params.Regex) + if err != nil { + return res, err + } + + timeout := time.Duration(common.Timeout) * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + ref, err := accntcli.ParseHostinfo(common.Hostname) + if err != nil { + return res, err + } + ref.SetUserinfo(common.Username, common.Password) + mw := accntcli.NewBasicAuthMiddleware(ref.Userinfo()) + cli := accntcli.NewClient(nil, mw) + + accounts, err := cli.ListAccounts(ctx, ref.Host()) + if err != nil { + return res, err + } + outAccounts := make([]descr.AccountShort, 0) + if params.Regex != "" { + for _, item := range accounts { + if outregex.MatchString(item.Username) { + outAccounts = append(outAccounts, item) + } + } + } else { + outAccounts = accounts + } + if params.Detail { + res.Accounts = outAccounts + } else { + res.Users = make([]Userinfo, 0) + for _, account := range outAccounts { + userinfo := Userinfo{ + Username: account.Username, + AccountID: account.ID, + Rights: make(map[string]string, 0), + } + for _, grant := range account.Grants { + userinfo.Rights[grant.ID] = grant.Right + } + res.Users = append(res.Users, userinfo) + } + } + return res, err +} diff --git a/cmd/mbasectl/accountcmd/listgrant.go b/cmd/mbasectl/accountcmd/listgrant.go new file mode 100644 index 0000000..5087783 --- /dev/null +++ b/cmd/mbasectl/accountcmd/listgrant.go @@ -0,0 +1,69 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "context" + "regexp" + "strings" + "time" + + "github.com/spf13/cobra" + + "mbase/pkg/accntcli" + "mbase/pkg/descr" +) + +// ListGrants +type ListGrantsParams struct { + Detail bool + AccountID string +} + +type ListGrantsResult struct { + Grants []descr.Grant `json:"grants,omitempty"` + Rights map[string]string `json:"rights,omitempty"` +} + +func (util *GrantUtil) ListGrants(cmd *cobra.Command, args []string) { + util.commonGrantParams.Hostname = args[0] + util.listGrantsParams.AccountID = args[1] + res, err := util.listGrants(&util.commonGrantParams, &util.listGrantsParams) + printResponse(res, err) +} +func (util *GrantUtil) listGrants(common *CommonGrantParams, params *ListGrantsParams) (*ListGrantsResult, error) { + var err error + res := &ListGrantsResult{} + + timeout := time.Duration(common.Timeout) * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + ref, err := accntcli.ParseHostinfo(common.Hostname) + if err != nil { + return res, err + } + ref.SetUserinfo(common.Username, common.Password) + mw := accntcli.NewBasicAuthMiddleware(ref.Userinfo()) + cli := accntcli.NewClient(nil, mw) + + grants := make([]descr.Grant, 0) + re := regexp.MustCompile(uuidRegex) + id := strings.ToLower(params.AccountID) + if re.MatchString(id) { + grants, err = cli.ListGrantsByAccountID(ctx, ref.Host(), id) + } else { + grants, err = cli.ListGrantsByUsername(ctx, ref.Host(), params.AccountID) + } + if err != nil { + return res, err + } + if params.Detail { + res.Grants = grants + } else { + res.Rights = make(map[string]string, 0) + for _, item := range grants { + res.Rights[item.ID] = item.Right + } + } + return res, err +} diff --git a/cmd/mbasectl/accountcmd/printresp.go b/cmd/mbasectl/accountcmd/printresp.go new file mode 100644 index 0000000..8ae2213 --- /dev/null +++ b/cmd/mbasectl/accountcmd/printresp.go @@ -0,0 +1,27 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "fmt" + + "sigs.k8s.io/yaml" +) + +func printResponse(res any, err error) { + 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"` + } + resp := Response{} + if err != nil { + resp.Error = true + resp.Message = err.Error() + } else { + resp.Result = res + } + respBytes, _ := yaml.Marshal(resp) + fmt.Printf("---\n%s\n", string(respBytes)) +} diff --git a/cmd/mbasectl/accountcmd/updacc.go b/cmd/mbasectl/accountcmd/updacc.go new file mode 100644 index 0000000..81bc6ea --- /dev/null +++ b/cmd/mbasectl/accountcmd/updacc.go @@ -0,0 +1,59 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "context" + "regexp" + "strings" + "time" + + "github.com/spf13/cobra" + + "mbase/pkg/accntcli" +) + +// UpdateAccount +type UpdateAccountParams struct { + Timeout uint64 + AccountID string + NewUsername string + NewPassword string +} +type UpdateAccountResult struct { +} + +func (util *AccountUtil) UpdateAccount(cmd *cobra.Command, args []string) { + util.commonAccountParams.Hostname = args[0] + util.updateAccountParams.AccountID = args[1] + res, err := util.updateAccount(&util.commonAccountParams, &util.updateAccountParams) + printResponse(res, err) +} + +func (util *AccountUtil) updateAccount(common *CommonAccountParams, params *UpdateAccountParams) (*UpdateAccountResult, error) { + var err error + res := &UpdateAccountResult{} + + timeout := time.Duration(common.Timeout) * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + ref, err := accntcli.ParseHostinfo(common.Hostname) + if err != nil { + return res, err + } + ref.SetUserinfo(common.Username, common.Password) + mw := accntcli.NewBasicAuthMiddleware(ref.Userinfo()) + cli := accntcli.NewClient(nil, mw) + + re := regexp.MustCompile(uuidRegex) + id := strings.ToLower(params.AccountID) + if re.MatchString(id) { + err = cli.UpdateAccountByID(ctx, ref.Host(), id, params.NewUsername, params.NewPassword) + } else { + err = cli.UpdateAccountByName(ctx, ref.Host(), params.AccountID, params.NewUsername, params.NewPassword) + } + if err != nil { + return res, err + } + return res, err +} diff --git a/cmd/mbasectl/accountcmd/updgrant.go b/cmd/mbasectl/accountcmd/updgrant.go new file mode 100644 index 0000000..54bb87c --- /dev/null +++ b/cmd/mbasectl/accountcmd/updgrant.go @@ -0,0 +1,51 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package accountcmd + +import ( + "context" + "strings" + "time" + + "github.com/spf13/cobra" + + "mbase/pkg/accntcli" +) + +// UpdateGrant +type UpdateGrantParams struct { + GrantID string + Pattern string +} +type UpdateGrantResult struct{} + +func (util *GrantUtil) UpdateGrant(cmd *cobra.Command, args []string) { + util.commonGrantParams.Hostname = args[0] + util.updateGrantParams.GrantID = args[1] + util.updateGrantParams.Pattern = args[2] + res, err := util.updateGrant(&util.commonGrantParams, &util.updateGrantParams) + printResponse(res, err) +} + +func (util *GrantUtil) updateGrant(common *CommonGrantParams, params *UpdateGrantParams) (*UpdateGrantResult, error) { + var err error + res := &UpdateGrantResult{} + + timeout := time.Duration(common.Timeout) * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + ref, err := accntcli.ParseHostinfo(common.Hostname) + if err != nil { + return res, err + } + ref.SetUserinfo(common.Username, common.Password) + mw := accntcli.NewBasicAuthMiddleware(ref.Userinfo()) + cli := accntcli.NewClient(nil, mw) + + id := strings.ToLower(params.GrantID) + err = cli.UpdateGrant(ctx, ref.Host(), id, params.Pattern) + 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..96b13af --- /dev/null +++ b/cmd/mbasectl/main.go @@ -0,0 +1,22 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package main + +import ( + "mbase/cmd/mbasectl/util" + "os" +) + +func main() { + var err error + util := util.NewUtil() + err = util.Build() + if err != nil { + os.Exit(1) + } + err = util.Exec(os.Args[1:]) + if err != nil { + os.Exit(1) + } +} diff --git a/cmd/mbasectl/util/util.go b/cmd/mbasectl/util/util.go new file mode 100644 index 0000000..bacb40f --- /dev/null +++ b/cmd/mbasectl/util/util.go @@ -0,0 +1,58 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package util + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/spf13/cobra" + + "mbase/cmd/mbasectl/accountcmd" +) + +type Util struct { + rootCmd *cobra.Command +} + +func NewUtil() *Util { + return &Util{} +} + +func (util *Util) GetRooCmd() *cobra.Command { + return util.rootCmd +} + +func (util *Util) Build() error { + var err error + execName := filepath.Base(os.Args[0]) + rootCmd := &cobra.Command{ + Use: execName, + Short: "\nOperation with artefacts: files, images, service accounts and grants", + SilenceUsage: true, + } + rootCmd.CompletionOptions.DisableDefaultCmd = true + + accountUtil := accountcmd.NewAccountUtil() + rootCmd.AddCommand(accountUtil.MakeAccountCmds()) + + grantUtil := accountcmd.NewGrantUtil() + rootCmd.AddCommand(grantUtil.MakeGrantCmds()) + + util.rootCmd = rootCmd + + return err +} + +func (util *Util) Exec(args []string) error { + var err error + util.rootCmd.SetArgs(args) + err = util.rootCmd.Execute() + return err +} + +func (util *Util) Hello(cmd *cobra.Command, args []string) { + fmt.Println("hello, world!") +} diff --git a/cmd/mbased/main.go b/cmd/mbased/main.go new file mode 100644 index 0000000..885ff31 --- /dev/null +++ b/cmd/mbased/main.go @@ -0,0 +1,42 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package main + +// @title Service API +// @version 1.0 +// @description API documentation + +// @contact.name API Support +// @contact.url http://www.swagger.io/support +// @contact.email support@swagger.io + +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html +// @query.collection.format multi + +// @host localhost +// @basePath / +// @schemes http https + +// @query.collection.format multi + +import ( + "os" + + "mbase/app/logger" + "mbase/cmd/mbased/starter" + + _ "mbase/app/handler" +) + +func main() { + log := logger.NewLoggerWithSubject("main") + sta := starter.NewStarter() + err := sta.Exec() + if err != nil { + log.Errorf("%v", err) + os.Exit(1) + } + os.Exit(0) +} diff --git a/cmd/mbased/starter/starter.go b/cmd/mbased/starter/starter.go new file mode 100644 index 0000000..19223e6 --- /dev/null +++ b/cmd/mbased/starter/starter.go @@ -0,0 +1,75 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package starter + +import ( + "os" + "path/filepath" + + "mbase/app/server" + + "github.com/spf13/cobra" +) + +type Starter struct { + runAsDaemon bool + port uint32 + cmd *cobra.Command + srv *server.Server +} + +func NewStarter() *Starter { + execName := filepath.Base(os.Args[0]) + sta := &Starter{} + cmd := &cobra.Command{ + Use: execName, + Short: "\nArtifact storage service", + SilenceUsage: true, + RunE: sta.run, + } + cmd.CompletionOptions.DisableDefaultCmd = true + cmd.Flags().BoolVarP(&sta.runAsDaemon, "asDaemon", "D", true, "Run service as daemon") + cmd.Flags().Uint32VarP(&sta.port, "port", "P", 1025, "Service port") + + sta.cmd = cmd + return sta +} + +func (sta *Starter) GetCmd() *cobra.Command { + return sta.cmd +} + +func (sta *Starter) run(cmd *cobra.Command, args []string) error { + var err error + srv, err := server.NewServer() + if err != nil { + return err + } + err = srv.Configure() + if err != nil { + return err + } + srv.SetAsDaemon(sta.runAsDaemon) + srv.SetPort(sta.port) + + err = srv.Daemonize() + if err != nil { + return err + } + + err = srv.Build() + if err != nil { + return err + } + err = srv.Run() + if err != nil { + return err + } + sta.srv = srv + return err +} + +func (sta *Starter) Exec() error { + return sta.cmd.Execute() +}