small fixes, refs #290

* do not populate auth servers advertising local ips
* fix annoying resize on session create
* decrease TTLs for active sessions and parties
This commit is contained in:
klizhentas 2016-03-23 11:12:24 -07:00
parent 9e98bde9ef
commit d42e122ef1
10 changed files with 99 additions and 56 deletions

View file

@ -10,11 +10,8 @@ PWD ?= $(shell pwd)
ETCD_CERTS := $(realpath fixtures/certs)
ETCD_FLAGS := TELEPORT_TEST_ETCD_CONFIG='{"nodes": ["https://localhost:4001"], "key":"/teleport/test", "tls_key_file": "$(ETCD_CERTS)/proxy1-key.pem", "tls_cert_file": "$(ETCD_CERTS)/proxy1.pem", "tls_ca_file": "$(ETCD_CERTS)/ca.pem"}'
TELEPORT_DEBUG_TESTS ?= no
GO15VENDOREXPERIMENT := 1
export
.PHONY: install test test-with-etcd remove-temp files test-package update test-grep-package cover-package cover-package-with-etcd run profile sloccount set-etcd
#
# Default target: builds all 3 executables and plaaces them in a current directory
#
@ -71,6 +68,7 @@ docs:
#
# tests everything: called by Jenkins
#
.PHONY: test
test: FLAGS ?= -cover
test:
go test -v $(PKGPATH)/tool/tsh/... \
@ -110,42 +108,55 @@ binary-release: build
cp -af $(BUILDDIR)/tctl $(BUILDDIR)/tsh $(BUILDDIR)/teleport $(BUILDDIR)/$(RELEASE)/teleport/build
tar -czf $(BUILDDIR)/$(RELEASE).tar.gz -C $(BUILDDIR)/$(RELEASE) teleport
.PHONY: flags
flags:
$(shell go install $(PKGPATH)/vendor/github.com/gravitational/version/cmd/linkflags)
$(eval BUILDFLAGS := $(ADDFLAGS) -ldflags "$(shell linkflags -pkg=$(GOPATH)/src/$(PKGPATH) -verpkg=$(PKGPATH)/vendor/github.com/gravitational/version)")
test-with-etcd: install
.PHONY: test-with-etcd
test-with-etcd: remove-temp-files
${ETCD_FLAGS} go test -v -test.parallel=0 $(shell go list ./... | grep -v /vendor/) -cover
test-package: remove-temp-files install
.PHONY: test-package
test-package: remove-temp-files
go test -v -test.parallel=0 ./$(p)
test-package-with-etcd: remove-temp-files install
.PHONY: tets-package-with-etcd
test-package-with-etcd: remove-temp-files
${ETCD_FLAGS} go test -v -test.parallel=0 ./$(p)
test-grep-package-with-etcd: remove-temp-files install
.PHONY: test-grep-package-with-etcd
test-grep-package-with-etcd: remove-temp-files
${ETCD_FLAGS} go test -v -test.parallel=0 ./$(p) -check.f=$(e)
test-grep-package: remove-temp-files install
.PHONY: test-grep-package
test-grep-package: remove-temp-files
go test -v ./$(p) -check.f=$(e)
.PHONY: cover-package
cover-package: remove-temp-files
go test -v ./$(p) -coverprofile=/tmp/coverage.out
go tool cover -html=/tmp/coverage.out
.PHONY: cover-package-with-etcd
cover-package-with-etcd: remove-temp-files
${ETCD_FLAGS} go test -v ./$(p) -coverprofile=/tmp/coverage.out
go tool cover -html=/tmp/coverage.out
.PHONY: profile
profile:
go tool pprof http://localhost:6060/debug/pprof/profile
.PHONY: sloccount
sloccount:
find . -path ./vendor -prune -o -name "*.go" -print0 | xargs -0 wc -l
# start-test-etcd starts test etcd node using tls certificates
.PHONY: start-test-etcd
start-test-etcd:
docker run -d -p 4001:4001 -p 2380:2380 -p 2379:2379 -v $(ETCD_CERTS):/certs quay.io/coreos/etcd:v2.2.5 -name etcd0 -advertise-client-urls https://localhost:2379,https://localhost:4001 -listen-client-urls https://0.0.0.0:2379,https://0.0.0.0:4001 -initial-advertise-peer-urls https://localhost:2380 -listen-peer-urls https://0.0.0.0:2380 -initial-cluster-token etcd-cluster-1 -initial-cluster etcd0=https://localhost:2380 -initial-cluster-state new --cert-file=/certs/etcd1.pem --key-file=/certs/etcd1-key.pem --peer-cert-file=/certs/etcd1.pem --peer-key-file=/certs/etcd1-key.pem --peer-client-cert-auth --peer-trusted-ca-file=/certs/ca.pem -client-cert-auth
.PHONY: remove-temp-files
remove-temp-files:
find . -name flymake_* -delete

View file

@ -613,12 +613,10 @@ func (c *TunClient) Dial(network, address string) (net.Conn, error) {
func (c *TunClient) fetchAndSync() error {
authServers, err := c.fetchAuthServers()
if err != nil {
log.Infof("failed to fetch auth servers")
return trace.Wrap(err)
}
if len(authServers) == 0 {
log.Warningf("no auth servers received")
return trace.Wrap(teleport.NotFound("no auth servers"))
return trace.Wrap(teleport.NotFound("no auth servers with remote ips advertised"))
}
// set runtime information about auth servers
c.setAuthServers(authServers)
@ -637,7 +635,7 @@ func (c *TunClient) syncAuthServers() {
case <-c.refreshTicker.C:
err := c.fetchAndSync()
if err != nil {
log.Infof("failed to fetch and sync servers: %v", err)
log.Infof("fetch and sync servers: %v", err)
continue
}
case <-c.closeC:
@ -657,7 +655,9 @@ func (c *TunClient) fetchAuthServers() ([]utils.NetAddr, error) {
if err != nil {
return nil, trace.Wrap(err)
}
authServers = append(authServers, *serverAddr)
if !serverAddr.IsLocal() {
authServers = append(authServers, *serverAddr)
}
}
return authServers, nil
}

View file

@ -83,7 +83,7 @@ const (
// SessionRefreshPeriod is how often tsh polls information about session
// TODO(klizhentas) all polling periods should go away once backend
// releases
// releases events
SessionRefreshPeriod = 2 * time.Second
// DefaultDialTimeout is a default TCP dial timeout we set for our
@ -125,6 +125,18 @@ const (
// MaxPasswordLength is maximum password length (for sanity)
MaxPasswordLength = 128
// IterationLimit is a default limit if it's not set
IterationLimit = 100
// MaxIterationLimit is max iteration limit
MaxIterationLimit = 1000
// ActiveSessionTTL is a TTL when session is marked as inactive
ActiveSessionTTL = 30 * time.Second
// ActivePartyTTL is a TTL when party is marked as inactive
ActivePartyTTL = 30 * time.Second
)
// Default connection limits, they can be applied separately on any of the Teleport

View file

@ -24,6 +24,7 @@ import (
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/lib/backend"
"github.com/gravitational/teleport/lib/defaults"
"github.com/docker/docker/pkg/term"
"github.com/gravitational/trace"
@ -137,15 +138,13 @@ func (p *Party) String() string {
)
}
// DefaultLimit is a default limit if it's not set
const DefaultLimit = 100
// TerminalParams holds parameters of the terminal used in session
type TerminalParams struct {
W int `json:"w"`
H int `json:"h"`
}
// String returns debug friendly representation of terminal
func (p *TerminalParams) String() string {
return fmt.Sprintf("TerminalParams(w=%v, h=%v)", p.W, p.H)
}
@ -245,14 +244,11 @@ func New(bk backend.Backend, opts ...Option) (Service, error) {
s.clock = &timetools.RealTime{}
}
if s.activeSessionTTL == 0 {
s.activeSessionTTL = DefaultActiveSessionTTL
s.activeSessionTTL = defaults.ActiveSessionTTL
}
return s, nil
}
// MaxLimit is max iteration limit
const MaxLimit = 1000
func activeBucket() []string {
return []string{"sessions", "active"}
}
@ -318,13 +314,6 @@ func (s *server) GetSession(id ID) (*Session, error) {
return sess, nil
}
const (
// DefaultActiveSessionTTL is a TTL when session is marked as inactive
DefaultActiveSessionTTL = 10 * time.Minute
// DefaultActivePartyTTL is a TTL when party is marked as inactive
DefaultActivePartyTTL = 10 * time.Second
)
// CreateSession creates a new session if it does not exist, if the session
// exists the function will return AlreadyExists error
// The session will be marked as active for TTL period of time

View file

@ -13,6 +13,7 @@ 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 session
import (
@ -20,8 +21,8 @@ import (
"testing"
"time"
// "github.com/gravitational/teleport"
"github.com/gravitational/teleport/lib/backend/boltbk"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/utils"
"github.com/mailgun/timetools"
@ -136,7 +137,7 @@ func (s *BoltSuite) TestSessionsInactivity(c *C) {
}
c.Assert(s.srv.CreateSession(sess), IsNil)
s.clock.Sleep(DefaultActiveSessionTTL + time.Second)
s.clock.Sleep(defaults.ActiveSessionTTL + time.Second)
sess.Active = false
s2, err := s.srv.GetSession(sess.ID)
@ -162,7 +163,7 @@ func (s *BoltSuite) TestPartiesCRUD(c *C) {
ServerID: "id-1",
LastActive: s.clock.UtcNow(),
}
c.Assert(s.srv.UpsertParty(sess.ID, p1, DefaultActivePartyTTL), IsNil)
c.Assert(s.srv.UpsertParty(sess.ID, p1, defaults.ActivePartyTTL), IsNil)
out, err := s.srv.GetSession(sess.ID)
c.Assert(err, IsNil)
@ -177,7 +178,7 @@ func (s *BoltSuite) TestPartiesCRUD(c *C) {
ServerID: "id-2",
LastActive: s.clock.UtcNow(),
}
c.Assert(s.srv.UpsertParty(sess.ID, p2, DefaultActivePartyTTL), IsNil)
c.Assert(s.srv.UpsertParty(sess.ID, p2, defaults.ActivePartyTTL), IsNil)
out, err = s.srv.GetSession(sess.ID)
c.Assert(err, IsNil)
@ -187,7 +188,7 @@ func (s *BoltSuite) TestPartiesCRUD(c *C) {
// Update session party
s.clock.Sleep(time.Second)
p1.LastActive = s.clock.UtcNow()
c.Assert(s.srv.UpsertParty(sess.ID, p1, DefaultActivePartyTTL), IsNil)
c.Assert(s.srv.UpsertParty(sess.ID, p1, defaults.ActivePartyTTL), IsNil)
out, err = s.srv.GetSession(sess.ID)
c.Assert(err, IsNil)

View file

@ -24,6 +24,7 @@ import (
"time"
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/events"
"github.com/gravitational/teleport/lib/recorder"
rsession "github.com/gravitational/teleport/lib/session"
@ -245,7 +246,7 @@ func (s *session) upsertSessionParty(sid rsession.ID, p *party) error {
ServerID: p.serverID,
RemoteAddr: p.site,
LastActive: p.getLastActive(),
}, rsession.DefaultActivePartyTTL)
}, defaults.ActivePartyTTL)
}
// startShell starts a new shell process in the current session

View file

@ -39,6 +39,15 @@ type NetAddr struct {
Path string `json:"path,omitempty"`
}
// IsLocal returns true if this is a local address
func (a *NetAddr) IsLocal() bool {
host, _, err := net.SplitHostPort(a.Addr)
if err != nil {
return false
}
return IsLocalHost(host)
}
// IsEmpty returns true if address is empty
func (a *NetAddr) IsEmpty() bool {
return a.Addr == "" && a.AddrNetwork == "" && a.Path == ""
@ -190,8 +199,7 @@ func ReplaceLocalhost(addr, replaceWith string) string {
if err != nil {
return addr
}
ip := net.ParseIP(host)
if ip.IsLoopback() || ip.IsUnspecified() {
if IsLocalHost(host) {
host, _, err = net.SplitHostPort(replaceWith)
if err != nil {
return addr
@ -200,3 +208,12 @@ func ReplaceLocalhost(addr, replaceWith string) string {
}
return addr
}
// IsLocalHost returns true if this is a local hostname or ip
func IsLocalHost(host string) bool {
if host == "localhost" {
return true
}
ip := net.ParseIP(host)
return ip.IsLoopback() || ip.IsUnspecified()
}

View file

@ -82,3 +82,23 @@ func (s *AddrTestSuite) TestReplaceLocalhost(c *C) {
result = ReplaceLocalhost("0.0.0.0:22", "192.168.1.100:399")
c.Assert(result, Equals, "192.168.1.100:22")
}
func (s *AddrTestSuite) TestLocalAddrs(c *C) {
testCases := []struct {
in string
expected bool
}{
{in: "127.0.0.1:5000", expected: true},
{in: "localhost:5000", expected: true},
{in: "127.0.0.2:5000", expected: true},
{in: "tcp://127.0.0.2:5000", expected: true},
{in: "tcp://10.0.0.3:5000", expected: false},
{in: "tcp://hostname:5000", expected: false},
}
for i, testCase := range testCases {
addr, err := ParseAddr(testCase.in)
c.Assert(err, IsNil)
c.Assert(addr.IsLocal(), Equals, testCase.expected,
Commentf("test case %v, %v should be local(%v)", i, testCase.in, testCase.expected))
}
}

View file

@ -142,8 +142,8 @@ func NewHandler(cfg Config, opts ...HandlerOption) (http.Handler, error) {
h.GET("/webapi/sites/:site/connect", h.withSiteAuth(h.siteNodeConnect))
// get session event stream
h.GET("/webapi/sites/:site/sessions/:sid/events/stream", h.withSiteAuth(h.siteSessionStream))
// create a new session
h.POST("/webapi/sites/:site/sessions", h.withSiteAuth(h.siteSessionCreate))
// generate a new session
h.POST("/webapi/sites/:site/sessions", h.withSiteAuth(h.siteSessionGenerate))
// update session parameters
h.PUT("/webapi/sites/:site/sessions/:sid", h.withSiteAuth(h.siteSessionUpdate))
// get session
@ -533,15 +533,15 @@ func (m *Handler) siteSessionStream(w http.ResponseWriter, r *http.Request, p ht
return nil, nil
}
type siteSessionCreateReq struct {
type siteSessionGenerateReq struct {
Session session.Session `json:"session"`
}
type siteSessionCreateResponse struct {
type siteSessionGenerateResponse struct {
Session session.Session `json:"session"`
}
// siteSessionCreate creates a new site session
// siteSessionCreate generates a new site session that can be used by UI
//
// POST /v1/webapi/sites/:site/sessions
//
@ -553,24 +553,16 @@ type siteSessionCreateResponse struct {
//
// {"session": {"id": "session-id", "terminal_params": {"w": 100, "h": 100}, "login": "centos"}}
//
func (m *Handler) siteSessionCreate(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *sessionContext, site reversetunnel.RemoteSite) (interface{}, error) {
var req *siteSessionCreateReq
func (m *Handler) siteSessionGenerate(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *sessionContext, site reversetunnel.RemoteSite) (interface{}, error) {
var req *siteSessionGenerateReq
if err := httplib.ReadJSON(r, &req); err != nil {
return nil, trace.Wrap(err)
}
client, err := ctx.GetClient()
if err != nil {
return nil, trace.Wrap(err)
}
req.Session.ID = session.NewID()
req.Session.Created = time.Now().UTC()
req.Session.LastActive = time.Now().UTC()
err = client.CreateSession(req.Session)
if err != nil {
return nil, trace.Wrap(err)
}
log.Infof("Created session: %#v", req.Session)
return siteSessionCreateResponse{Session: req.Session}, nil
log.Infof("Generated session: %#v", req.Session)
return siteSessionGenerateResponse{Session: req.Session}, nil
}
type siteSessionUpdateReq struct {

View file

@ -687,11 +687,11 @@ func (s *WebSuite) TestCreateSession(c *C) {
re, err := pack.clt.PostJSON(
pack.clt.Endpoint("webapi", "sites", s.domainName, "sessions"),
siteSessionCreateReq{Session: sess},
siteSessionGenerateReq{Session: sess},
)
c.Assert(err, IsNil)
var created *siteSessionCreateResponse
var created *siteSessionGenerateResponse
c.Assert(json.Unmarshal(re.Bytes(), &created), IsNil)
c.Assert(created.Session.ID, Not(Equals), "")
}