Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/admin/v2/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func AddCmds(cmd *cobra.Command, c *config.Config) {
adminCmd.AddCommand(newTaskCmd(c))
adminCmd.AddCommand(newTenantCmd(c))
adminCmd.AddCommand(newTokenCmd(c))
adminCmd.AddCommand(newVPNCmd(c))

cmd.AddCommand(adminCmd)
}
120 changes: 120 additions & 0 deletions cmd/admin/v2/vpn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package v2

import (
"fmt"
"strconv"
"time"

adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2"
apiv2 "github.com/metal-stack/api/go/metalstack/api/v2"
"github.com/metal-stack/cli/cmd/config"
"github.com/metal-stack/cli/cmd/sorters"
"github.com/metal-stack/metal-lib/pkg/genericcli"
"github.com/metal-stack/metal-lib/pkg/genericcli/printers"
"github.com/metal-stack/metal-lib/pkg/pointer"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"google.golang.org/protobuf/types/known/durationpb"
)

type vpn struct {
c *config.Config
}

func newVPNCmd(c *config.Config) *cobra.Command {
w := &vpn{
c: c,
}

cmdsConfig := &genericcli.CmdsConfig[any, any, *apiv2.VPNNode]{
BinaryName: config.BinaryName,
GenericCLI: genericcli.NewGenericCLI(w).WithFS(c.Fs),
Singular: "vpn",
Plural: "vpn",
Description: "manage vpn keys and list nodes connected",
Sorter: sorters.VpnNodeSorter(),
DescribePrinter: func() printers.Printer { return c.DescribePrinter },
ListPrinter: func() printers.Printer { return c.ListPrinter },
ListCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().String("project", "", "the project for which vpn nodes should be listed")
genericcli.Must(cmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion))
},
OnlyCmds: genericcli.OnlyCmds(genericcli.ListCmd),
ValidArgsFn: w.c.Completion.ProjectListCompletion,
}

authKeyCmd := &cobra.Command{
Use: "auth-key",
Short: "generate an auth key to connect to the vpn",
RunE: func(cmd *cobra.Command, args []string) error {
return w.authKey()
},
ValidArgsFunction: c.Completion.ProjectListCompletion,
}
authKeyCmd.Flags().String("project", "", "the project for which the authkey should be generated")
authKeyCmd.Flags().String("reason", "", "the reason why the authkey should be generated")
authKeyCmd.Flags().Bool("ephemeral", true, "ephemeral defines if the key can only be used once")
authKeyCmd.Flags().Duration("expires", 1*time.Hour, "the duration after the generated key is not valid anymore")
genericcli.Must(authKeyCmd.MarkFlagRequired("project"))
genericcli.Must(authKeyCmd.RegisterFlagCompletionFunc("project", c.Completion.ProjectListCompletion))

return genericcli.NewCmds(cmdsConfig, authKeyCmd)
}

func (v *vpn) authKey() error {
ctx, cancel := v.c.NewRequestContext()
defer cancel()

req := &adminv2.VPNServiceAuthKeyRequest{
Project: viper.GetString("project"),
Ephemeral: viper.GetBool("ephemeral"),
Expires: durationpb.New(viper.GetDuration("expires")),
Reason: viper.GetString("reason"),
}

resp, err := v.c.Client.Adminv2().VPN().AuthKey(ctx, req)
if err != nil {
return err
}

_, _ = fmt.Fprintf(v.c.Out, "auth-key: %s\n", resp.AuthKey)
_, _ = fmt.Fprintf(v.c.Out, "vpn-endpoint: %s\n", resp.Address)
_, _ = fmt.Fprintf(v.c.Out, "ephemeral: %s\n", strconv.FormatBool(resp.Ephemeral))
_, _ = fmt.Fprintf(v.c.Out, "expires in: %s\n", time.Until(resp.ExpiresAt.AsTime()))

return nil
}

func (v *vpn) Get(id string) (*apiv2.VPNNode, error) {
panic("unimplemented")
}

func (v *vpn) List() ([]*apiv2.VPNNode, error) {
ctx, cancel := v.c.NewRequestContext()
defer cancel()

resp, err := v.c.Client.Adminv2().VPN().ListNodes(ctx, &adminv2.VPNServiceListNodesRequest{
Project: pointer.PointerOrNil(viper.GetString("project")),
})
if err != nil {
return nil, fmt.Errorf("failed to list vpn nodes: %w", err)
}

return resp.Nodes, nil
}

func (v *vpn) Create(rq any) (*apiv2.VPNNode, error) {
panic("unimplemented")
}

func (v *vpn) Delete(id string) (*apiv2.VPNNode, error) {
panic("unimplemented")
}

func (v *vpn) Convert(r *apiv2.VPNNode) (string, any, any, error) {
panic("unimplemented")
}

func (v *vpn) Update(rq any) (*apiv2.VPNNode, error) {
panic("unimplemented")
}
20 changes: 20 additions & 0 deletions cmd/sorters/vpn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package sorters

import (
apiv2 "github.com/metal-stack/api/go/metalstack/api/v2"
"github.com/metal-stack/metal-lib/pkg/multisort"
)

func VpnNodeSorter() *multisort.Sorter[*apiv2.VPNNode] {
return multisort.New(multisort.FieldMap[*apiv2.VPNNode]{
"id": func(a, b *apiv2.VPNNode, descending bool) multisort.CompareResult {
return multisort.Compare(a.Id, b.Id, descending)
},
"name": func(a, b *apiv2.VPNNode, descending bool) multisort.CompareResult {
return multisort.Compare(a.Name, b.Name, descending)
},
"project": func(a, b *apiv2.VPNNode, descending bool) multisort.CompareResult {
return multisort.Compare(a.Project, b.Project, descending)
},
}, multisort.Keys{{ID: "id"}})
}
5 changes: 5 additions & 0 deletions cmd/tableprinters/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ func (t *TablePrinter) ToHeaderAndRows(data any, wide bool) ([]string, [][]strin
case []*apiv2.User:
return t.UserTable(d, wide)

case *apiv2.VPNNode:
return t.VPNTable(pointer.WrapInSlice(d), wide)
case []*apiv2.VPNNode:
return t.VPNTable(d, wide)

default:
return nil, nil, fmt.Errorf("unknown table printer for type: %T", d)
}
Expand Down
37 changes: 37 additions & 0 deletions cmd/tableprinters/vpn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package tableprinters

import (
"fmt"
"strings"
"time"

apiv2 "github.com/metal-stack/api/go/metalstack/api/v2"
)

func (t *TablePrinter) VPNTable(data []*apiv2.VPNNode, _ bool) ([]string, [][]string, error) {
var (
rows [][]string
header = []string{"ID", "Name", "Project", "IPS", "Last Seed"}
)

for _, node := range data {
var (
lastSeen = node.LastSeen.AsTime().Format(time.DateTime)
ips = strings.Join(node.IpAddresses, ",")
)

row := []string{
fmt.Sprintf("%d", node.Id),
node.Name,
node.Project,
ips,
lastSeen,
}

rows = append(rows, row)
}

t.t.DisableAutoWrap(false)

return header, rows, nil
}
1 change: 1 addition & 0 deletions docs/admin/metalctlv2_admin.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ these commands utilize the admin api, which can only be accessed by metal-stack
* [metalctlv2 admin task](metalctlv2_admin_task.md) - manage task entities
* [metalctlv2 admin tenant](metalctlv2_admin_tenant.md) - manage tenant entities
* [metalctlv2 admin token](metalctlv2_admin_token.md) - manage token entities
* [metalctlv2 admin vpn](metalctlv2_admin_vpn.md) - manage vpn entities

33 changes: 33 additions & 0 deletions docs/admin/metalctlv2_admin_vpn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## metalctlv2 admin vpn

manage vpn entities

### Synopsis

manage vpn keys and list nodes connected

### Options

```
-h, --help help for vpn
```

### Options inherited from parent commands

```
--api-token string the token used for api requests
--api-url string the url to the metal-stack.io api
-c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml)
--debug debug output
--force-color force colored output even without tty
-o, --output-format string output format (table|wide|markdown|json|yaml|template), wide is a table with more columns. (default "table")
--template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference.
--timeout duration request timeout used for api requests
```

### SEE ALSO

* [metalctlv2 admin](metalctlv2_admin.md) - admin commands
* [metalctlv2 admin vpn auth-key](metalctlv2_admin_vpn_auth-key.md) - generate an auth key to connect to the vpn
* [metalctlv2 admin vpn list](metalctlv2_admin_vpn_list.md) - list all vpn

35 changes: 35 additions & 0 deletions docs/admin/metalctlv2_admin_vpn_auth-key.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## metalctlv2 admin vpn auth-key

generate an auth key to connect to the vpn

```
metalctlv2 admin vpn auth-key [flags]
```

### Options

```
--ephemeral ephemeral defines if the key can only be used once (default true)
--expires duration the duration after the generated key is not valid anymore (default 1h0m0s)
-h, --help help for auth-key
--project string the project for which the authkey should be generated
--reason string the reason why the authkey should be generated
```

### Options inherited from parent commands

```
--api-token string the token used for api requests
--api-url string the url to the metal-stack.io api
-c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml)
--debug debug output
--force-color force colored output even without tty
-o, --output-format string output format (table|wide|markdown|json|yaml|template), wide is a table with more columns. (default "table")
--template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference.
--timeout duration request timeout used for api requests
```

### SEE ALSO

* [metalctlv2 admin vpn](metalctlv2_admin_vpn.md) - manage vpn entities

33 changes: 33 additions & 0 deletions docs/admin/metalctlv2_admin_vpn_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## metalctlv2 admin vpn list

list all vpn

```
metalctlv2 admin vpn list [flags]
```

### Options

```
-h, --help help for list
--project string the project for which vpn nodes should be listed
--sort-by strings sort by (comma separated) column(s), sort direction can be changed by appending :asc or :desc behind the column identifier. possible values: id|name|project
```

### Options inherited from parent commands

```
--api-token string the token used for api requests
--api-url string the url to the metal-stack.io api
-c, --config string alternative config file path, (default is ~/.metal-stack/config.yaml)
--debug debug output
--force-color force colored output even without tty
-o, --output-format string output format (table|wide|markdown|json|yaml|template), wide is a table with more columns. (default "table")
--template string output template for template output-format, go template format. For property names inspect the output of -o json or -o yaml for reference.
--timeout duration request timeout used for api requests
```

### SEE ALSO

* [metalctlv2 admin vpn](metalctlv2_admin_vpn.md) - manage vpn entities

Loading
Loading