Skip to content

Commit

Permalink
✨ Add port forward subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
gabe565 committed Mar 23, 2022
1 parent eba76d2 commit eb3ea08
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"github.com/clevyr/kubedb/cmd/dump"
"github.com/clevyr/kubedb/cmd/exec"
"github.com/clevyr/kubedb/cmd/port_forward"
"github.com/clevyr/kubedb/cmd/restore"
"github.com/clevyr/kubedb/internal/config/flags"
log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -80,6 +81,7 @@ func init() {
exec.Command,
dump.Command,
restore.Command,
port_forward.Command,
)
}

Expand Down
110 changes: 110 additions & 0 deletions cmd/port_forward/port_forward.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package port_forward

import (
"fmt"
"github.com/clevyr/kubedb/internal/config"
"github.com/clevyr/kubedb/internal/util"
"github.com/jedib0t/go-pretty/v6/table"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/client-go/tools/portforward"
"k8s.io/client-go/transport/spdy"
"net/http"
"net/url"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
)

var Command = &cobra.Command{
Use: "port-forward [local_port]",
Short: "set up a local port forward",
RunE: run,
PreRunE: preRun,
}

var conf config.PortForward

func preRun(cmd *cobra.Command, args []string) error {
err := util.DefaultSetup(cmd, &conf.Global)
if err != nil {
return err
}

if len(args) == 0 {
conf.LocalPort = conf.Grammar.DefaultPort()
} else {
port, err := strconv.ParseUint(args[0], 10, 16)
if err != nil {
return err
}
conf.LocalPort = uint16(port)
}
return nil
}

func run(cmd *cobra.Command, args []string) (err error) {
log.WithField("pod", conf.Pod.Name).Info("setting up port forward")

path := fmt.Sprintf(
"/api/v1/namespaces/%s/pods/%s/portforward",
conf.Pod.Namespace,
conf.Pod.Name,
)
hostIP := strings.TrimLeft(conf.Client.ClientConfig.Host, "htps:/")

transport, upgrader, err := spdy.RoundTripperFor(conf.Client.ClientConfig)
if err != nil {
return err
}

dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, http.MethodPost, &url.URL{Scheme: "https", Path: path, Host: hostIP})
stopCh := make(chan struct{}, 1)
readyCh := make(chan struct{}, 1)
ports := []string{fmt.Sprintf("%d:%d", conf.LocalPort, conf.Grammar.DefaultPort())}
fw, err := portforward.New(dialer, ports, stopCh, readyCh, nil, os.Stderr)
if err != nil {
return err
}

go func() {
<-readyCh
log.WithFields(log.Fields{
"local": conf.LocalPort,
"remote": conf.Grammar.DefaultPort(),
}).Info("port forward is ready")
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.SetTitle("%s Connection Parameters", conf.Pod.Namespace)
t.AppendRows([]table.Row{
{"Hostname", "localhost"},
{"Port", conf.LocalPort},
{"Username", conf.Username},
{"Password", conf.Password},
{"Database", conf.Database},
})
t.SetStyle(table.StyleLight)
t.Render()
}()

errCh := make(chan error, 1)
go func() {
errCh <- fw.ForwardPorts()
}()

interruptCh := make(chan os.Signal, 1)
signal.Notify(interruptCh, os.Interrupt, syscall.SIGTERM)
select {
case err = <-errCh:
if err != nil {
return err
}
case <-interruptCh:
log.Info("received exit signal")
close(stopCh)
}
return nil
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.18
require (
github.com/AlecAivazis/survey/v2 v2.3.2
github.com/docker/cli v20.10.11+incompatible
github.com/jedib0t/go-pretty/v6 v6.2.7
github.com/schollz/progressbar/v3 v3.8.6
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.2.1
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jedib0t/go-pretty/v6 v6.2.7 h1:4823Lult/tJ0VI1PgW3aSKw59pMWQ6Kzv9b3Bj6MwY0=
github.com/jedib0t/go-pretty/v6 v6.2.7/go.mod h1:FMkOpgGD3EZ91cW8g/96RfxoV7bdeJyzXPYgz1L1ln0=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
Expand Down Expand Up @@ -336,6 +338,7 @@ github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down Expand Up @@ -519,6 +522,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
1 change: 1 addition & 0 deletions internal/config/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

type Databaser interface {
Name() string
DefaultPort() uint16

DatabaseEnvNames() []string
DefaultDatabase() string
Expand Down
6 changes: 6 additions & 0 deletions internal/config/port_forward.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package config

type PortForward struct {
Global
LocalPort uint16
}
5 changes: 5 additions & 0 deletions internal/database/grammar/mariadb.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ type MariaDB struct{}
func (MariaDB) Name() string {
return "mariadb"
}

func (MariaDB) DefaultPort() uint16 {
return 3306
}

func (MariaDB) DatabaseEnvNames() []string {
return []string{"MARIADB_DATABASE"}
}
Expand Down
4 changes: 4 additions & 0 deletions internal/database/grammar/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ func (Postgres) Name() string {
return "postgres"
}

func (Postgres) DefaultPort() uint16 {
return 5432
}

func (Postgres) DatabaseEnvNames() []string {
return []string{"POSTGRES_DB"}
}
Expand Down

0 comments on commit eb3ea08

Please sign in to comment.