Skip to content
New issue

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

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

Already on GitHub? # to your account

Client application draft #66

Merged
merged 3 commits into from
Dec 30, 2015
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
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ install: teleport
teleport: remove-temp-files
go install github.com/gravitational/teleport/tool/teleport
go install github.com/gravitational/teleport/tool/tctl
go install github.com/gravitational/teleport/tool/tsh

test: install
go test -v -test.parallel=0 ./... -cover
Expand All @@ -19,18 +20,18 @@ test-with-etcd: install
remove-temp-files:
find . -name flymake_* -delete

test-package: remove-temp-files
test-package: remove-temp-files install
go test -v -test.parallel=0 ./$(p)

test-package-with-etcd: remove-temp-files
test-package-with-etcd: remove-temp-files install
${ETCD_FLAGS} go test -v -test.parallel=0 ./$(p)

update:
rm -rf Godeps/
find . -iregex .*go | xargs sed -i 's:".*Godeps/_workspace/src/:":g'
godep save -r ./...

test-grep-package: remove-temp-files
test-grep-package: remove-temp-files install
go test -v ./$(p) -check.f=$(e)

cover-package: remove-temp-files
Expand Down
2 changes: 1 addition & 1 deletion examples/embedded.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ssh:
# enable simple ssh endpoint
enabled: true
limiter:
max_connections: 2
max_connections: 10000
rates:
- period: 20s
average: 3
Expand Down
21 changes: 13 additions & 8 deletions lib/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,31 +229,36 @@ func ConnectToNode(nodeAddress string, authMethod ssh.AuthMethod, user string) (
}

// Shell returns remote shell as io.ReadWriterCloser object
func (client *NodeClient) Shell() (io.ReadWriteCloser, error) {
func (client *NodeClient) Shell(width, height int) (io.ReadWriteCloser, error) {
session, err := client.Client.NewSession()
if err != nil {
return nil, trace.Wrap(err)
}

terminalModes := ssh.TerminalModes{}

err = session.RequestPty("xterm", height, width, terminalModes)
if err != nil {
return nil, trace.Wrap(err)
}

writer, err := session.StdinPipe()
if err != nil {
return nil, trace.Wrap(err)
}

// Here we can use session.StdoutPipe() instead of Buffer,
// but according to the ssh godoc:
// "If the StdoutPipe reader is not serviced fast
// enough it may eventually cause the remote command to block."
stdout := &bytes.Buffer{}
session.Stdout = stdout
reader, err := session.StdoutPipe()
if err != nil {
return nil, trace.Wrap(err)
}

err = session.Shell()
if err != nil {
return nil, trace.Wrap(err)
}

return utils.NewPipeNetConn(
stdout,
reader,
writer,
utils.MultiCloser(writer, session),
&net.IPAddr{},
Expand Down
10 changes: 6 additions & 4 deletions lib/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ func (s *ClientSuite) TestShell(c *C) {
s.teleagent.AuthMethod(), s.user)
c.Assert(err, IsNil)

shell, err := nodeClient.Shell()
shell, err := nodeClient.Shell(100, 100)
c.Assert(err, IsNil)

// run first command
Expand Down Expand Up @@ -327,7 +327,7 @@ func (s *ClientSuite) TestGetServer(c *C) {
"cmdLabel1": services.CommandLabel{
Period: time.Second,
Command: []string{"expr", "1", "+", "3"},
Result: "4\n",
Result: "4",
},
},
}
Expand All @@ -343,12 +343,12 @@ func (s *ClientSuite) TestGetServer(c *C) {
"cmdLabel1": services.CommandLabel{
Period: time.Second,
Command: []string{"expr", "1", "+", "4"},
Result: "5\n",
Result: "5",
},
"cmdLabel2": services.CommandLabel{
Period: time.Second,
Command: []string{"expr", "1", "+", "5"},
Result: "6\n",
Result: "6",
},
},
}
Expand Down Expand Up @@ -461,6 +461,7 @@ func (s *ClientSuite) TestUploadDir(c *C) {
contents2 := []byte("this is content 2")

err = ioutil.WriteFile(sourceFileName1, contents1, 0666)
c.Assert(err, IsNil)
err = ioutil.WriteFile(sourceFileName2, contents2, 0666)
c.Assert(err, IsNil)

Expand Down Expand Up @@ -490,6 +491,7 @@ func (s *ClientSuite) TestDownloadDir(c *C) {
contents2 := []byte("this is content 2")

err = ioutil.WriteFile(sourceFileName1, contents1, 0666)
c.Assert(err, IsNil)
err = ioutil.WriteFile(sourceFileName2, contents2, 0666)
c.Assert(err, IsNil)

Expand Down
3 changes: 3 additions & 0 deletions lib/srv/srv.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ func (s *Server) updateLabel(name string, label services.CommandLabel) {
log.Errorf(err.Error())
label.Result = err.Error() + " Output: " + string(out)
} else {
if out[len(out)-1] == 10 {
out = out[:len(out)-1] // remove new line
}
label.Result = string(out)
}
s.labelsMutex.Lock()
Expand Down
2 changes: 1 addition & 1 deletion lib/srv/srv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ func (s *SrvSuite) TestProxy(c *C) {
<-done
c.Assert(stdout.String(), Equals,
`{"localhost":[{"id":"127.0.0.1_30185","addr":"127.0.0.1:30185","hostname":"localhost","labels":null,"cmd_labels":null},`+
`{"id":"127.0.0.1_31185","addr":"127.0.0.1:31185","hostname":"localhost","labels":{"label1":"value1"},"cmd_labels":{"cmdLabel1":{"period":"1s","command":["expr","1","+","3"],"result":"4\n"}}}]}`)
`{"id":"127.0.0.1_31185","addr":"127.0.0.1:31185","hostname":"localhost","labels":{"label1":"value1"},"cmd_labels":{"cmdLabel1":{"period":"1s","command":["expr","1","+","3"],"result":"4"}}}]}`)

}

Expand Down
32 changes: 32 additions & 0 deletions tool/tsh/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Copyright 2015 Gravitational, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main

import (
"os"

"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/log"
"github.com/gravitational/teleport/tool/tsh/tsh"
)

func main() {
log.Initialize("console", "INFO")

err := tsh.RunTSH(os.Args)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RunTSH is a bit redundant(because of the package name), how about simply Run

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, but there is Run() function in the test(check.v1) package

if err != nil {
log.Errorf(err.Error())
}
}
91 changes: 91 additions & 0 deletions tool/tsh/tsh/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
Copyright 2015 Gravitational, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package tsh

import (
"net"

"github.com/gravitational/teleport/Godeps/_workspace/src/github.com/gravitational/trace"
"github.com/gravitational/teleport/Godeps/_workspace/src/golang.org/x/crypto/ssh/agent"
"github.com/gravitational/teleport/Godeps/_workspace/src/gopkg.in/alecthomas/kingpin.v2"
)

func RunTSH(args []string) error {
app := kingpin.New("tsh", "teleport SSH client")

user := app.Flag("user", "SSH user").Required().String()
sshAgentAddress := app.Flag("ssh-agent", "SSH agent address").OverrideDefaultFromEnvar("SSH_AUTH_SOCK").String()
sshAgentNetwork := app.Flag("ssh-agent-network", "SSH agent address network type('tcp','unix' etc.)").Default("unix").String()

connect := app.Command("connect", "Helper operations with SSH keypairs")
connectAddress := connect.Arg("address", "Target server address").Required().String()
connectProxy := connect.Flag("proxy", "Optional proxy address").String()
connectCommand := connect.Flag("command", "Run proveded command instead of shell").String()

upload := app.Command("upload", "Helper operations with SSH keypairs")
uploadAddress := upload.Arg("address", "Target server address").Required().String()
uploadProxy := upload.Flag("proxy", "Optional proxy address").String()
uploadLocalSource := upload.Flag("source", "Local source path").Required().String()
uploadRemoteDest := upload.Flag("dest", "Remote destination path").Required().String()

download := app.Command("download", "Helper operations with SSH keypairs")
downloadAddress := download.Arg("address", "Target server address").Required().String()
downloadProxy := download.Flag("proxy", "Optional proxy address").String()
downloadLocalDest := download.Flag("dest", "Local destination path").Required().String()
downloadRemoteSource := download.Flag("source", "Remote source path").Required().String()
downloadRecursively := download.Flag("r", "Source path is directory").Bool()

getServers := app.Command("get-servers", "Returns list of servers")
getServersProxy := getServers.Flag("proxy", "Target proxy address").String()
getServersLabelName := getServers.Flag("label", "Label name").String()
getServersLabelValue := getServers.Flag("value", "Label value regexp").String()

selectedCommand := kingpin.MustParse(app.Parse(args[1:]))

agent, err := connectToSSHAgent(*sshAgentNetwork, *sshAgentAddress)
if err != nil {
return trace.Wrap(err)
}

err = trace.Errorf("No command")

switch selectedCommand {
case connect.FullCommand():
err = Connect(*user, *connectAddress, *connectProxy, *connectCommand, agent)
case upload.FullCommand():
err = Upload(*user, *uploadAddress, *uploadProxy, *uploadLocalSource,
*uploadRemoteDest, agent)
case download.FullCommand():
err = Download(*user, *downloadAddress, *downloadProxy,
*downloadRemoteSource, *downloadLocalDest,
*downloadRecursively, agent)
case getServers.FullCommand():
err = GetServers(*user, *getServersProxy, *getServersLabelName,
*getServersLabelValue, agent)
}

return err
}

func connectToSSHAgent(network, address string) (agent.Agent, error) {
conn, err := net.Dial(network, address)
if err != nil {
return nil, trace.Wrap(err)
}

return agent.NewClient(conn), nil

}
Loading