mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
feat: add 'ctx ls' command to list available cluster contexts in config
This commit is contained in:
@@ -0,0 +1,61 @@
|
|||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
"text/tabwriter"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewListCommand() *cobra.Command {
|
||||||
|
var clusterContext string
|
||||||
|
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "list",
|
||||||
|
Aliases: []string{"ls"},
|
||||||
|
Short: "List available cluster contexts.",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return list(uncli)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Flags().StringVarP(
|
||||||
|
&clusterContext, "context", "c", "",
|
||||||
|
"Name of the cluster context. (default is the current context)",
|
||||||
|
)
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func list(uncli *cli.CLI) error {
|
||||||
|
if uncli.Config == nil {
|
||||||
|
return fmt.Errorf("context management is not available: Uncloud configuration file is not being used")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(uncli.Config.Contexts) == 0 {
|
||||||
|
fmt.Println("No contexts found")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
contextNames := slices.Sorted(maps.Keys(uncli.Config.Contexts))
|
||||||
|
currentContext := uncli.Config.CurrentContext
|
||||||
|
|
||||||
|
tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
|
||||||
|
fmt.Fprintln(tw, "NAME\tCURRENT\tCONNECTIONS")
|
||||||
|
|
||||||
|
for _, name := range contextNames {
|
||||||
|
current := ""
|
||||||
|
if name == currentContext {
|
||||||
|
current = "*"
|
||||||
|
}
|
||||||
|
connCount := len(uncli.Config.Contexts[name].Connections)
|
||||||
|
fmt.Fprintf(tw, "%s\t%s\t%d\n", name, current, connCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tw.Flush()
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewRootCommand() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "context",
|
||||||
|
Aliases: []string{"ctx"},
|
||||||
|
Short: "Switch between different cluster contexts. Contains subcommands to manage contexts.",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
// TODO
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.AddCommand(
|
||||||
|
NewListCommand(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/cmd/uncloud/caddy"
|
"github.com/psviderski/uncloud/cmd/uncloud/caddy"
|
||||||
|
cmdcontext "github.com/psviderski/uncloud/cmd/uncloud/context"
|
||||||
"github.com/psviderski/uncloud/cmd/uncloud/dns"
|
"github.com/psviderski/uncloud/cmd/uncloud/dns"
|
||||||
"github.com/psviderski/uncloud/cmd/uncloud/machine"
|
"github.com/psviderski/uncloud/cmd/uncloud/machine"
|
||||||
"github.com/psviderski/uncloud/cmd/uncloud/service"
|
"github.com/psviderski/uncloud/cmd/uncloud/service"
|
||||||
@@ -67,10 +68,12 @@ func main() {
|
|||||||
cmd.PersistentFlags().StringVar(&opts.configPath, "uncloud-config", "~/.config/uncloud/config.yaml",
|
cmd.PersistentFlags().StringVar(&opts.configPath, "uncloud-config", "~/.config/uncloud/config.yaml",
|
||||||
"Path to the Uncloud configuration file.")
|
"Path to the Uncloud configuration file.")
|
||||||
_ = cmd.MarkPersistentFlagFilename("uncloud-config", "yaml", "yml")
|
_ = cmd.MarkPersistentFlagFilename("uncloud-config", "yaml", "yml")
|
||||||
|
// TODO: make --context a global flag and pass it as a value of the command context.
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
NewDeployCommand(),
|
NewDeployCommand(),
|
||||||
caddy.NewRootCommand(),
|
caddy.NewRootCommand(),
|
||||||
|
cmdcontext.NewRootCommand(),
|
||||||
dns.NewRootCommand(),
|
dns.NewRootCommand(),
|
||||||
machine.NewRootCommand(),
|
machine.NewRootCommand(),
|
||||||
service.NewRootCommand(),
|
service.NewRootCommand(),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
func NewRootCommand() *cobra.Command {
|
func NewRootCommand() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "service",
|
Use: "service",
|
||||||
|
Aliases: []string{"svc"},
|
||||||
Short: "Manage services in an Uncloud cluster.",
|
Short: "Manage services in an Uncloud cluster.",
|
||||||
}
|
}
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
|
|||||||
+27
-27
@@ -24,7 +24,7 @@ import (
|
|||||||
const defaultContextName = "default"
|
const defaultContextName = "default"
|
||||||
|
|
||||||
type CLI struct {
|
type CLI struct {
|
||||||
config *config.Config
|
Config *config.Config
|
||||||
conn *config.MachineConnection
|
conn *config.MachineConnection
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,26 +42,26 @@ func New(configPath string, conn *config.MachineConnection) (*CLI, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &CLI{
|
return &CLI{
|
||||||
config: cfg,
|
Config: cfg,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *CLI) CreateContext(name string) error {
|
func (cli *CLI) CreateContext(name string) error {
|
||||||
if _, ok := cli.config.Contexts[name]; ok {
|
if _, ok := cli.Config.Contexts[name]; ok {
|
||||||
return fmt.Errorf("context '%s' already exists", name)
|
return fmt.Errorf("context '%s' already exists", name)
|
||||||
}
|
}
|
||||||
cli.config.Contexts[name] = &config.Context{
|
cli.Config.Contexts[name] = &config.Context{
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
return cli.config.Save()
|
return cli.Config.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *CLI) SetCurrentContext(name string) error {
|
func (cli *CLI) SetCurrentContext(name string) error {
|
||||||
if _, ok := cli.config.Contexts[name]; !ok {
|
if _, ok := cli.Config.Contexts[name]; !ok {
|
||||||
return api.ErrNotFound
|
return api.ErrNotFound
|
||||||
}
|
}
|
||||||
cli.config.CurrentContext = name
|
cli.Config.CurrentContext = name
|
||||||
return cli.config.Save()
|
return cli.Config.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectCluster connects to a cluster using the given context name or the current context if not specified.
|
// ConnectCluster connects to a cluster using the given context name or the current context if not specified.
|
||||||
@@ -71,42 +71,42 @@ func (cli *CLI) ConnectCluster(ctx context.Context, contextName string) (*client
|
|||||||
return connectCluster(ctx, *cli.conn)
|
return connectCluster(ctx, *cli.conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cli.config.Contexts) == 0 {
|
if len(cli.Config.Contexts) == 0 {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"no cluster contexts found in the Uncloud config (%s). "+
|
"no cluster contexts found in the Uncloud config (%s). "+
|
||||||
"Please initialise a cluster with 'uncloud machine init' first",
|
"Please initialise a cluster with 'uncloud machine init' first",
|
||||||
cli.config.Path(),
|
cli.Config.Path(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if contextName == "" {
|
if contextName == "" {
|
||||||
// If the cluster is not specified, use the current cluster if set.
|
// If the cluster is not specified, use the current cluster if set.
|
||||||
if cli.config.CurrentContext == "" {
|
if cli.Config.CurrentContext == "" {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"the current cluster context is not set in the Uncloud config (%s). "+
|
"the current cluster context is not set in the Uncloud config (%s). "+
|
||||||
"Please specify the context with the '--context' flag or set 'current_context' in the config",
|
"Please specify the context with the '--context' flag or set 'current_context' in the config",
|
||||||
cli.config.Path(),
|
cli.Config.Path(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if _, ok := cli.config.Contexts[cli.config.CurrentContext]; !ok {
|
if _, ok := cli.Config.Contexts[cli.Config.CurrentContext]; !ok {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"current cluster context '%s' not found in the Uncloud config (%s). "+
|
"current cluster context '%s' not found in the Uncloud config (%s). "+
|
||||||
"Please specify the context with the '--context' flag or update 'current_context' in the config",
|
"Please specify the context with the '--context' flag or update 'current_context' in the config",
|
||||||
cli.config.CurrentContext,
|
cli.Config.CurrentContext,
|
||||||
cli.config.Path(),
|
cli.Config.Path(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
contextName = cli.config.CurrentContext
|
contextName = cli.Config.CurrentContext
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, ok := cli.config.Contexts[contextName]
|
cfg, ok := cli.Config.Contexts[contextName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("cluster context '%s' not found in the Uncloud config (%s)",
|
return nil, fmt.Errorf("cluster context '%s' not found in the Uncloud config (%s)",
|
||||||
contextName, cli.config.Path())
|
contextName, cli.Config.Path())
|
||||||
}
|
}
|
||||||
if len(cfg.Connections) == 0 {
|
if len(cfg.Connections) == 0 {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"no connection configurations found for cluster context '%s' in the Uncloud config (%s)",
|
"no connection configurations found for cluster context '%s' in the Uncloud config (%s)",
|
||||||
contextName, cli.config.Path(),
|
contextName, cli.Config.Path(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ func (cli *CLI) initRemoteMachine(
|
|||||||
if contextName == "" {
|
if contextName == "" {
|
||||||
contextName = defaultContextName
|
contextName = defaultContextName
|
||||||
}
|
}
|
||||||
if _, ok := cli.config.Contexts[contextName]; ok {
|
if _, ok := cli.Config.Contexts[contextName]; ok {
|
||||||
return nil, fmt.Errorf("cluster %q already exists", contextName)
|
return nil, fmt.Errorf("cluster %q already exists", contextName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,12 +216,12 @@ func (cli *CLI) initRemoteMachine(
|
|||||||
return nil, fmt.Errorf("init cluster: %w", err)
|
return nil, fmt.Errorf("init cluster: %w", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Cluster initialised with machine '%s' and saved as context '%s' in your local config (%s)\n",
|
fmt.Printf("Cluster initialised with machine '%s' and saved as context '%s' in your local config (%s)\n",
|
||||||
resp.Machine.Name, contextName, cli.config.Path())
|
resp.Machine.Name, contextName, cli.Config.Path())
|
||||||
if err = cli.CreateContext(contextName); err != nil {
|
if err = cli.CreateContext(contextName); err != nil {
|
||||||
return nil, fmt.Errorf("save cluster context to config: %w", err)
|
return nil, fmt.Errorf("save cluster context to config: %w", err)
|
||||||
}
|
}
|
||||||
// Set the current cluster to the just created one if it is the only cluster in the config.
|
// Set the current cluster to the just created one if it is the only cluster in the config.
|
||||||
if len(cli.config.Contexts) == 1 {
|
if len(cli.Config.Contexts) == 1 {
|
||||||
if err = cli.SetCurrentContext(contextName); err != nil {
|
if err = cli.SetCurrentContext(contextName); err != nil {
|
||||||
return nil, fmt.Errorf("set current cluster context: %w", err)
|
return nil, fmt.Errorf("set current cluster context: %w", err)
|
||||||
}
|
}
|
||||||
@@ -232,8 +232,8 @@ func (cli *CLI) initRemoteMachine(
|
|||||||
SSH: config.NewSSHDestination(remoteMachine.User, remoteMachine.Host, remoteMachine.Port),
|
SSH: config.NewSSHDestination(remoteMachine.User, remoteMachine.Host, remoteMachine.Port),
|
||||||
SSHKeyFile: remoteMachine.KeyPath,
|
SSHKeyFile: remoteMachine.KeyPath,
|
||||||
}
|
}
|
||||||
cli.config.Contexts[contextName].Connections = append(cli.config.Contexts[contextName].Connections, connCfg)
|
cli.Config.Contexts[contextName].Connections = append(cli.Config.Contexts[contextName].Connections, connCfg)
|
||||||
if err = cli.config.Save(); err != nil {
|
if err = cli.Config.Save(); err != nil {
|
||||||
return nil, fmt.Errorf("save config: %w", err)
|
return nil, fmt.Errorf("save config: %w", err)
|
||||||
}
|
}
|
||||||
return machineClient, nil
|
return machineClient, nil
|
||||||
@@ -335,10 +335,10 @@ func (cli *CLI) AddMachine(
|
|||||||
SSHKeyFile: remoteMachine.KeyPath,
|
SSHKeyFile: remoteMachine.KeyPath,
|
||||||
}
|
}
|
||||||
if contextName == "" {
|
if contextName == "" {
|
||||||
contextName = cli.config.CurrentContext
|
contextName = cli.Config.CurrentContext
|
||||||
}
|
}
|
||||||
cli.config.Contexts[contextName].Connections = append(cli.config.Contexts[contextName].Connections, connCfg)
|
cli.Config.Contexts[contextName].Connections = append(cli.Config.Contexts[contextName].Connections, connCfg)
|
||||||
if err = cli.config.Save(); err != nil {
|
if err = cli.Config.Save(); err != nil {
|
||||||
return nil, fmt.Errorf("save config: %w", err)
|
return nil, fmt.Errorf("save config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user