Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

give example in manual usage instructions #44

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
44 changes: 29 additions & 15 deletions connector/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,31 @@ Username: {{.User}}
Password: {{.Pass}}
Name: {{.Name}}

Leave this terminal open while you want to use the SSH tunnel. Press Control-C to stop.
{{if .HasRepl }}To connect:

{{.LaunchCmd}}

{{end}}Leave this terminal open while you want to use the SSH tunnel. Press Control-C to stop.
`

type localConnectionData struct {
Port int
User string
Pass string
Name string
Port int
User string
Pass string
Name string
HasRepl bool
LaunchCmd service.LaunchCmd
}

func manualConnect(tunnel launcher.SSHTunnel, creds models.Credentials) (err error) {
func manualConnect(srv service.Service, tunnel launcher.SSHTunnel, creds models.Credentials) (err error) {
launchCmd := srv.GetLaunchCmd(tunnel.LocalPort, creds)
connectionData := localConnectionData{
Port: tunnel.LocalPort,
User: creds.GetUsername(),
Pass: creds.GetPassword(),
Name: creds.GetDBName(),
Port: tunnel.LocalPort,
User: creds.GetUsername(),
Pass: creds.GetPassword(),
Name: creds.GetDBName(),
HasRepl: srv.HasRepl(),
LaunchCmd: launchCmd,
}

tmpl, err := template.New("").Parse(manualConnectInstructions)
Expand All @@ -66,17 +75,22 @@ func handleClient(
si models.ServiceInstance,
creds models.Credentials,
) error {
srv := service.GetService(si)
if srv == service.UnknownService {
fmt.Printf("Unable to find matching client for service '%s' with plan '%s'.\n", si.Service, si.Plan)
}

if options.ConnectClient {
srv, found := service.GetService(si)
if found {
if srv.HasRepl() {
cmd := srv.GetLaunchCmd(tunnel.LocalPort, creds)
fmt.Println("Connecting client...")
return srv.Launch(tunnel.LocalPort, creds)
return cmd.Exec()
}

fmt.Printf("Unable to find matching client for service '%s' with plan '%s'. Falling back to `-no-client` behavior.\n", si.Service, si.Plan)
fmt.Println("Falling back to `-no-client` behavior.")
}

return manualConnect(tunnel, creds)
return manualConnect(srv, tunnel, creds)
}

// Connect performs the primary action of the plugin: providing an SSH tunnel and launching the appropriate client, if desired.
Expand Down
37 changes: 37 additions & 0 deletions service/launch_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package service

import (
"os"
"strings"

"github.com/18F/cf-service-connect/launcher"
)

type LaunchCmd struct {
Envs map[string]string
Cmd string
Args []string
}

func (lc LaunchCmd) Exec() error {
for envVar, val := range lc.Envs {
err := os.Setenv(envVar, val)
if err != nil {
return err
}
}

return launcher.StartShell(lc.Cmd, lc.Args)
}

func (lc LaunchCmd) String() string {
result := ""
for envVar, val := range lc.Envs {
result += envVar + "=" + val + " "
}
result += lc.Cmd
if len(lc.Args) > 0 {
result += " " + strings.Join(lc.Args, " ")
}
return result
}
44 changes: 44 additions & 0 deletions service/launch_cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package service

import (
"testing"

"github.com/bruth/assert"
)

type launchCmdStringTest struct {
LaunchCmd LaunchCmd
Expected string
}

func TestLaunchCmdString(t *testing.T) {
tests := []launchCmdStringTest{
launchCmdStringTest{
LaunchCmd: LaunchCmd{
Cmd: "foo",
},
Expected: "foo",
},
launchCmdStringTest{
LaunchCmd: LaunchCmd{
Envs: map[string]string{
"a": "1",
"b": "2",
},
Cmd: "foo",
},
Expected: "a=1 b=2 foo",
},
launchCmdStringTest{
LaunchCmd: LaunchCmd{
Cmd: "foo",
Args: []string{"bar", "baz"},
},
Expected: "foo bar baz",
},
}

for _, test := range tests {
assert.Equal(t, test.LaunchCmd.String(), test.Expected)
}
}
22 changes: 14 additions & 8 deletions service/mongo_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package service
import (
"strconv"

"github.com/18F/cf-service-connect/launcher"
"github.com/18F/cf-service-connect/models"
)

Expand All @@ -13,13 +12,20 @@ func (p mongoDB) Match(si models.ServiceInstance) bool {
return si.ContainsTerms("mongo")
}

func (p mongoDB) Launch(localPort int, creds models.Credentials) error {
return launcher.StartShell("mongo", []string{
"-u", creds.GetUsername(),
"-p", creds.GetPassword(),
"--port", strconv.Itoa(localPort),
creds.GetDBName(),
})
func (p mongoDB) HasRepl() bool {
return true
}

func (p mongoDB) GetLaunchCmd(localPort int, creds models.Credentials) LaunchCmd {
return LaunchCmd{
Cmd: "mongo",
Args: []string{
"-u", creds.GetUsername(),
"-p", creds.GetPassword(),
"--port", strconv.Itoa(localPort),
creds.GetDBName(),
},
}
}

// MongoDB is the service singleton.
Expand Down
24 changes: 15 additions & 9 deletions service/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package service
import (
"strconv"

"github.com/18F/cf-service-connect/launcher"
"github.com/18F/cf-service-connect/models"
)

Expand All @@ -13,14 +12,21 @@ func (p mySQL) Match(si models.ServiceInstance) bool {
return si.ContainsTerms("mysql")
}

func (p mySQL) Launch(localPort int, creds models.Credentials) error {
return launcher.StartShell("mysql", []string{
"-u", creds.GetUsername(),
"-h", "0",
"-p" + creds.GetPassword(),
"-D", creds.GetDBName(),
"-P", strconv.Itoa(localPort),
})
func (p mySQL) HasRepl() bool {
return true
}

func (p mySQL) GetLaunchCmd(localPort int, creds models.Credentials) LaunchCmd {
return LaunchCmd{
Cmd: "mysql",
Args: []string{
"-u", creds.GetUsername(),
"-h", "0",
"-p" + creds.GetPassword(),
"-D", creds.GetDBName(),
"-P", strconv.Itoa(localPort),
},
}
}

// MySQL is the service singleton.
Expand Down
28 changes: 16 additions & 12 deletions service/psql.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package service

import (
"fmt"
"os"

"github.com/18F/cf-service-connect/launcher"
"github.com/18F/cf-service-connect/logger"
"github.com/18F/cf-service-connect/models"
)

Expand All @@ -15,16 +12,23 @@ func (p pSQL) Match(si models.ServiceInstance) bool {
return si.ContainsTerms("psql", "postgres")
}

func (p pSQL) Launch(localPort int, creds models.Credentials) error {
os.Setenv("PGPASSWORD", creds.GetPassword())
logger.Debugf("PGPASSWORD=%s ", creds.GetPassword())
func (p pSQL) HasRepl() bool {
return true
}

return launcher.StartShell("psql", []string{
"-h", "localhost",
"-p", fmt.Sprintf("%d", localPort),
creds.GetDBName(),
creds.GetUsername(),
})
func (p pSQL) GetLaunchCmd(localPort int, creds models.Credentials) LaunchCmd {
return LaunchCmd{
Envs: map[string]string{
"PGPASSWORD": creds.GetPassword(),
},
Cmd: "psql",
Args: []string{
"-h", "localhost",
"-p", fmt.Sprintf("%d", localPort),
creds.GetDBName(),
creds.GetUsername(),
},
}
}

// PSQL is the service singleton.
Expand Down
18 changes: 12 additions & 6 deletions service/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package service
import (
"strconv"

"github.com/18F/cf-service-connect/launcher"
"github.com/18F/cf-service-connect/models"
)

Expand All @@ -13,11 +12,18 @@ func (p redis) Match(si models.ServiceInstance) bool {
return si.ContainsTerms("redis")
}

func (p redis) Launch(localPort int, creds models.Credentials) error {
return launcher.StartShell("redis-cli", []string{
"-p", strconv.Itoa(localPort),
"-a", creds.GetPassword(),
})
func (p redis) HasRepl() bool {
return true
}

func (p redis) GetLaunchCmd(localPort int, creds models.Credentials) LaunchCmd {
return LaunchCmd{
Cmd: "redis-cli",
Args: []string{
"-p", strconv.Itoa(localPort),
"-a", creds.GetPassword(),
},
}
}

// Redis is the service singleton.
Expand Down
9 changes: 5 additions & 4 deletions service/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import "github.com/18F/cf-service-connect/models"

type Service interface {
Match(si models.ServiceInstance) bool
Launch(localPort int, creds models.Credentials) error
HasRepl() bool
GetLaunchCmd(localPort int, creds models.Credentials) LaunchCmd
}

var services = []Service{
Expand All @@ -14,12 +15,12 @@ var services = []Service{
Redis,
}

func GetService(si models.ServiceInstance) (Service, bool) {
func GetService(si models.ServiceInstance) Service {
for _, potentialService := range services {
if potentialService.Match(si) {
return potentialService, true
return potentialService
}
}

return nil, false
return UnknownService
}
13 changes: 3 additions & 10 deletions service/services_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
type getServiceTest struct {
serviceName string
planName string
expectFound bool
expectService Service
}

Expand All @@ -19,20 +18,17 @@ func TestGetService(t *testing.T) {
{
"psql",
"shared",
true,
PSQL,
},
{
"mysql",
"shared",
true,
MySQL,
},
{
"other",
"service",
false,
nil,
UnknownService,
},
}

Expand All @@ -41,11 +37,8 @@ func TestGetService(t *testing.T) {
Service: test.serviceName,
Plan: test.planName,
}
srv, found := GetService(serviceInstance)
assert.Equal(t, found, test.expectFound)
if test.expectFound {
assert.Equal(t, srv, test.expectService)
}
srv := GetService(serviceInstance)
assert.Equal(t, srv, test.expectService)
}

}
26 changes: 26 additions & 0 deletions service/unknown_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package service

import (
"github.com/18F/cf-service-connect/models"
)

type unknownService struct{}

func (p unknownService) Match(si models.ServiceInstance) bool {
return true
}

func (p unknownService) HasRepl() bool {
return false
}

func (p unknownService) GetLaunchCmd(localPort int, creds models.Credentials) LaunchCmd {
return LaunchCmd{
// no-op
// https://stackoverflow.com/a/12405621/358804
Cmd: ":",
}
}

// UnknownService is the service singleton.
var UnknownService = unknownService{}