command_port

package
v0.24.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 21, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ForwardCmd = &cli.Command{
	Name:        "forward",
	Usage:       "Forward a port from one space to another",
	Description: "Forward a port from one space to a port in another space.",
	Arguments: []cli.Argument{
		&cli.StringArg{
			Name:     "from-space",
			Usage:    "The name of the source space",
			Required: true,
		},
		&cli.IntArg{
			Name:     "from-port",
			Usage:    "The port in the source space to forward from",
			Required: true,
		},
		&cli.StringArg{
			Name:     "to-space",
			Usage:    "The name of the target space",
			Required: true,
		},
		&cli.IntArg{
			Name:     "to-port",
			Usage:    "The port in the target space to forward to",
			Required: true,
		},
	},
	Flags: []cli.Flag{
		&cli.BoolFlag{
			Name:    "persistent",
			Aliases: []string{"p"},
			Usage:   "Persist the port forward across agent restarts",
		},
		&cli.BoolFlag{
			Name:    "force",
			Aliases: []string{"f"},
			Usage:   "Create the forward even if the target space is not currently running",
		},
	},
	MaxArgs: cli.NoArgs,
	Run: func(ctx context.Context, cmd *cli.Command) error {
		fromSpace := cmd.GetStringArg("from-space")
		fromPort := cmd.GetIntArg("from-port")
		toSpace := cmd.GetStringArg("to-space")
		toPort := cmd.GetIntArg("to-port")

		if fromPort < 1 || fromPort > 65535 {
			return fmt.Errorf("invalid from-port: must be between 1 and 65535")
		}
		if toPort < 1 || toPort > 65535 {
			return fmt.Errorf("invalid to-port: must be between 1 and 65535")
		}

		client, err := cmdutil.GetClient(cmd)
		if err != nil {
			return fmt.Errorf("failed to create API client: %w", err)
		}

		spaces, _, err := client.GetSpaces(ctx, "")
		if err != nil {
			return fmt.Errorf("failed to get spaces: %w", err)
		}

		var fromSpaceInfo *apiclient.SpaceInfo
		for i := range spaces.Spaces {
			if spaces.Spaces[i].Name == fromSpace {
				fromSpaceInfo = &spaces.Spaces[i]
				break
			}
		}

		if fromSpaceInfo == nil {
			return fmt.Errorf("space '%s' not found", fromSpace)
		}

		if !fromSpaceInfo.IsDeployed || !fromSpaceInfo.HasState {
			if !cmd.GetBool("persistent") {
				return fmt.Errorf("space '%s' is not running", fromSpace)
			}
		}

		if !cmd.GetBool("force") {
			var toSpaceInfo *apiclient.SpaceInfo
			for i := range spaces.Spaces {
				if spaces.Spaces[i].Name == toSpace {
					toSpaceInfo = &spaces.Spaces[i]
					break
				}
			}
			if toSpaceInfo == nil {
				return fmt.Errorf("space '%s' not found", toSpace)
			}
			if !toSpaceInfo.IsDeployed || !toSpaceInfo.HasState {
				return fmt.Errorf("space '%s' is not running", toSpace)
			}
		}

		spaceId := fromSpaceInfo.Id

		// Resolve target space name to ID
		var toSpaceId string
		for i := range spaces.Spaces {
			if spaces.Spaces[i].Name == toSpace {
				toSpaceId = spaces.Spaces[i].Id
				break
			}
		}
		if toSpaceId == "" {
			return fmt.Errorf("space '%s' not found", toSpace)
		}

		force := cmd.GetBool("force")

		request := &apiclient.PortForwardRequest{
			LocalPort:  uint16(fromPort),
			Space:      toSpaceId,
			RemotePort: uint16(toPort),
			Persistent: cmd.GetBool("persistent"),
			Force:      force,
		}

		code, err := client.ForwardPort(ctx, spaceId, request)
		if err != nil {
			if code == 401 {
				return fmt.Errorf("failed to authenticate with server, check token")
			} else if code == 403 {
				return fmt.Errorf("no permission to forward ports")
			} else if code == 404 {
				return fmt.Errorf("space not found")
			} else if code == 409 {
				return fmt.Errorf("space is not running, only persistent forwards can be created for stopped spaces")
			}
			return fmt.Errorf("port forward failed: %w", err)
		}

		fmt.Printf("Port forward established: %s:%d -> %s:%d\n", fromSpace, fromPort, toSpace, toPort)
		return nil
	},
}
View Source
var ListCmd = &cli.Command{
	Name:        "list",
	Usage:       "List active port forwards for a space",
	Description: "List all active port forwards from a space.",
	Arguments: []cli.Argument{
		&cli.StringArg{
			Name:     "space",
			Usage:    "The name of the space",
			Required: true,
		},
	},
	MaxArgs: cli.NoArgs,
	Run: func(ctx context.Context, cmd *cli.Command) error {
		spaceName := cmd.GetStringArg("space")

		client, err := cmdutil.GetClient(cmd)
		if err != nil {
			return fmt.Errorf("failed to create API client: %w", err)
		}

		spaces, _, err := client.GetSpaces(ctx, "")
		if err != nil {
			return fmt.Errorf("failed to get spaces: %w", err)
		}

		var spaceId string
		for _, s := range spaces.Spaces {
			if s.Name == spaceName {
				spaceId = s.Id
				break
			}
		}

		if spaceId == "" {
			return fmt.Errorf("space '%s' not found", spaceName)
		}

		response, code, err := client.ListPorts(ctx, spaceId)
		if err != nil {
			if code == 401 {
				return fmt.Errorf("failed to authenticate with server, check token")
			} else if code == 403 {
				return fmt.Errorf("no permission to list port forwards")
			} else if code == 404 {
				return fmt.Errorf("space not found")
			}
			return fmt.Errorf("failed to list port forwards: %w", err)
		}

		if len(response.Forwards) == 0 {
			fmt.Printf("No active port forwards in space '%s'.\n", spaceName)
			return nil
		}

		spaceNames := make(map[string]string, len(spaces.Spaces))
		for _, s := range spaces.Spaces {
			spaceNames[s.Id] = s.Name
		}

		fmt.Printf("Active port forwards in space '%s':\n", spaceName)
		for _, fwd := range response.Forwards {
			mode := "temporary"
			if fwd.Persistent {
				mode = "persistent"
			}

			target := fwd.Space
			if name, ok := spaceNames[fwd.Space]; ok {
				target = name
			}
			fmt.Printf("  %d -> %s:%d (%s)\n", fwd.LocalPort, target, fwd.RemotePort, mode)
		}

		return nil
	},
}
View Source
var PortCmd = &cli.Command{
	Name:        "port",
	Usage:       "Manage port forwarding between spaces",
	Description: "Forward ports from one space to another.",
	Flags: []cli.Flag{
		&cli.StringFlag{
			Name:    "server",
			Aliases: []string{"s"},
			Usage:   "The address of the remote server to manage spaces on.",
			EnvVars: []string{config.CONFIG_ENV_PREFIX + "_SERVER"},
			Global:  true,
		},
		&cli.StringFlag{
			Name:    "token",
			Aliases: []string{"t"},
			Usage:   "The token to use for authentication.",
			EnvVars: []string{config.CONFIG_ENV_PREFIX + "_TOKEN"},
			Global:  true,
		},
		&cli.BoolFlag{
			Name:         "tls-skip-verify",
			Usage:        "Skip TLS verification when talking to server.",
			ConfigPath:   []string{"tls.skip_verify"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_TLS_SKIP_VERIFY"},
			DefaultValue: true,
			Global:       true,
		},
		&cli.StringFlag{
			Name:         "alias",
			Aliases:      []string{"a"},
			Usage:        "The server alias to use.",
			DefaultValue: "default",
			Global:       true,
		},
	},
	Commands: []*cli.Command{
		ForwardCmd,
		ListCmd,
		StopCmd,
	},
}
View Source
var StopCmd = &cli.Command{
	Name:        "stop",
	Usage:       "Stop a port forward",
	Description: "Stop an active port forward by local port number.",
	Arguments: []cli.Argument{
		&cli.StringArg{
			Name:     "space",
			Usage:    "The name of the space",
			Required: true,
		},
		&cli.IntArg{
			Name:     "local-port",
			Usage:    "The local port to stop forwarding",
			Required: true,
		},
	},
	MaxArgs: cli.NoArgs,
	Run: func(ctx context.Context, cmd *cli.Command) error {
		spaceName := cmd.GetStringArg("space")
		localPort := cmd.GetIntArg("local-port")

		if localPort < 1 || localPort > 65535 {
			return fmt.Errorf("invalid local-port: must be between 1 and 65535")
		}

		client, err := cmdutil.GetClient(cmd)
		if err != nil {
			return fmt.Errorf("failed to create API client: %w", err)
		}

		spaces, _, err := client.GetSpaces(ctx, "")
		if err != nil {
			return fmt.Errorf("failed to get spaces: %w", err)
		}

		var spaceId string
		for _, s := range spaces.Spaces {
			if s.Name == spaceName {
				spaceId = s.Id
				break
			}
		}

		if spaceId == "" {
			return fmt.Errorf("space '%s' not found", spaceName)
		}

		request := &apiclient.PortStopRequest{
			LocalPort: uint16(localPort),
		}

		code, err := client.StopPort(ctx, spaceId, request)
		if err != nil {
			if code == 401 {
				return fmt.Errorf("failed to authenticate with server, check token")
			} else if code == 403 {
				return fmt.Errorf("no permission to stop port forwards")
			} else if code == 404 {
				return fmt.Errorf("space not found")
			}
			return fmt.Errorf("failed to stop port forward: %w", err)
		}

		fmt.Printf("Port forward on port %d stopped in space '%s'.\n", localPort, spaceName)
		return nil
	},
}

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL