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

Add helper for checking local peers #4159

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Expand Up @@ -183,7 +183,8 @@ you can run those with `task test-unit` after starting the environment as descri

We also have a set of "integration" tests in the `integration` directory.
They use the Go MongoDB driver like a regular user application.
They could test any MongoDB-compatible database (such as FerretDB or MongoDB itself) via a regular TCP or TLS port or Unix socket.
They could test any MongoDB-compatible database (such as FerretDB or MongoDB itself) via a regular TCP or TLS port
or Unix domain socket.
They also could test in-process FerretDB instances
(meaning that integration tests start and stop them themselves) with a given backend.
Finally, some integration tests (so-called compatibility or "compat" tests) connect to two systems
Expand Down
2 changes: 1 addition & 1 deletion ferretdb/ferretdb.go
Expand Up @@ -214,7 +214,7 @@ func (f *FerretDB) MongoDBURI() string {
Path: "/",
}
case f.config.Listener.Unix != "":
// MongoDB really wants Unix socket path in the host part of the URI
// MongoDB really wants Unix domain socket path in the host part of the URI
u = &url.URL{
Scheme: "mongodb",
Host: f.l.UnixAddr().String(),
Expand Down
2 changes: 1 addition & 1 deletion integration/commands_diagnostic_test.go
Expand Up @@ -403,7 +403,7 @@ func TestCommandsDiagnosticWhatsMyURI(t *testing.T) {
databaseName := s.Collection.Database().Name()
collectionName := s.Collection.Name()

// only check port number on TCP connection, no need to check on Unix socket
// only check port number on TCP connection, no need to check on Unix domain socket
isUnix := s.IsUnixSocket(t)

// setup second client connection to check that `whatsmyuri` returns different ports
Expand Down
6 changes: 3 additions & 3 deletions integration/setup/setup.go
Expand Up @@ -45,7 +45,7 @@ var (

targetProxyAddrF = flag.String("target-proxy-addr", "", "in-process FerretDB: use given proxy")
targetTLSF = flag.Bool("target-tls", false, "in-process FerretDB: use TLS")
targetUnixSocketF = flag.Bool("target-unix-socket", false, "in-process FerretDB: use Unix socket")
targetUnixSocketF = flag.Bool("target-unix-socket", false, "in-process FerretDB: use Unix domain socket")

postgreSQLURLF = flag.String("postgresql-url", "", "in-process FerretDB: PostgreSQL URL for 'postgresql' handler.")
sqliteURLF = flag.String("sqlite-url", "", "in-process FerretDB: SQLite URI for 'sqlite' handler.")
Expand Down Expand Up @@ -97,12 +97,12 @@ type SetupResult struct {
MongoDBURI string
}

// IsUnixSocket returns true if MongoDB URI is a Unix socket.
// IsUnixSocket returns true if MongoDB URI is a Unix domain socket.
func (s *SetupResult) IsUnixSocket(tb testtb.TB) bool {
tb.Helper()

// we can't use a regular url.Parse because
// MongoDB really wants Unix socket path in the host part of the URI
// MongoDB really wants Unix domain socket path in the host part of the URI
opts := options.Client().ApplyURI(s.MongoDBURI)
res := slices.ContainsFunc(opts.Hosts, func(host string) bool {
return strings.Contains(host, "/")
Expand Down
6 changes: 5 additions & 1 deletion internal/clientconn/conn.go
Expand Up @@ -24,6 +24,7 @@
"fmt"
"io"
"net"
"net/netip"
"os"
"path/filepath"
"runtime/pprof"
Expand Down Expand Up @@ -140,7 +141,10 @@

connInfo := conninfo.New()
if c.netConn.RemoteAddr().Network() != "unix" {
connInfo.PeerAddr = c.netConn.RemoteAddr().String()
connInfo.Peer, err = netip.ParseAddrPort(c.netConn.RemoteAddr().String())
if err != nil {
return

Check warning on line 146 in internal/clientconn/conn.go

View check run for this annotation

Codecov / codecov/patch

internal/clientconn/conn.go#L146

Added line #L146 was not covered by tests
}
}

ctx = conninfo.Ctx(ctx, connInfo)
Expand Down
26 changes: 17 additions & 9 deletions internal/clientconn/conninfo/conn_info.go
Expand Up @@ -17,6 +17,7 @@ package conninfo

import (
"context"
"net/netip"
"sync"

"github.com/xdg-go/scram"
Expand All @@ -32,28 +33,35 @@ var connInfoKey = contextKey{}
type ConnInfo struct {
// the order of fields is weird to make the struct smaller due to alignment

PeerAddr string
username string // protected by rw
password string // protected by rw
metadataRecv bool // protected by rw

sc *scram.ServerConversation // protected by rw

Peer netip.AddrPort // invalid for Unix domain sockets

username string // protected by rw
password string // protected by rw

rw sync.RWMutex

metadataRecv bool // protected by rw

// If true, backend implementations should not perform authentication
// by adding username and password to the connection string.
// It is set to true for background connections (such us capped collections cleanup)
// and by the new authentication mechanism.
// See where it is used for more details.
bypassBackendAuth bool // protected by rw

rw sync.RWMutex
}

// New returns a new ConnInfo.
func New() *ConnInfo {
return new(ConnInfo)
}

// LocalPeer returns whether the peer is considered local (using Unix domain socket or loopback IP).
func (connInfo *ConnInfo) LocalPeer() bool {
return !connInfo.Peer.IsValid() || connInfo.Peer.Addr().IsLoopback()
}

// Username returns stored username.
func (connInfo *ConnInfo) Username() string {
connInfo.rw.RLock()
Expand Down Expand Up @@ -89,8 +97,8 @@ func (connInfo *ConnInfo) Conv() *scram.ServerConversation {

// SetConv stores the SCRAM server conversation.
func (connInfo *ConnInfo) SetConv(sc *scram.ServerConversation) {
connInfo.rw.RLock()
defer connInfo.rw.RUnlock()
connInfo.rw.Lock()
defer connInfo.rw.Unlock()
Comment on lines +100 to +101
Copy link
Member Author

Choose a reason for hiding this comment

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

Oops!

Copy link
Contributor

Choose a reason for hiding this comment

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

Ouch


connInfo.username = sc.Username()
connInfo.sc = sc
Expand Down
23 changes: 14 additions & 9 deletions internal/clientconn/conninfo/conn_info_test.go
Expand Up @@ -16,6 +16,7 @@ package conninfo

import (
"context"
"net/netip"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -25,26 +26,30 @@ func TestGet(t *testing.T) {
t.Parallel()

for name, tc := range map[string]struct {
peerAddr string
peer netip.AddrPort
local bool
}{
"EmptyPeerAddr": {
peerAddr: "",
"Unix": {
local: true,
},
"NonEmptyPeerAddr": {
peerAddr: "127.0.0.8:1234",
"Local": {
peer: netip.MustParseAddrPort("127.42.7.1:1234"),
local: true,
},
"NonLocal": {
peer: netip.MustParseAddrPort("192.168.0.1:1234"),
local: false,
},
} {
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()

ctx := context.Background()
connInfo := &ConnInfo{
PeerAddr: tc.peerAddr,
Peer: tc.peer,
}
ctx = Ctx(ctx, connInfo)
actual := Get(ctx)
assert.Equal(t, connInfo, actual)
assert.Equal(t, tc.local, actual.LocalPeer())
})
}

Expand Down
2 changes: 1 addition & 1 deletion internal/handler/msg_whatsmyuri.go
Expand Up @@ -28,7 +28,7 @@ func (h *Handler) MsgWhatsMyURI(ctx context.Context, msg *wire.OpMsg) (*wire.OpM
var reply wire.OpMsg
must.NoError(reply.SetSections(wire.MakeOpMsgSection(
must.NotFail(types.NewDocument(
"you", conninfo.Get(ctx).PeerAddr,
"you", conninfo.Get(ctx).Peer.String(),
"ok", float64(1),
)),
)))
Expand Down
Expand Up @@ -33,7 +33,7 @@ In the latest release, we have published our commands parity guide with MongoDB,

## Bug Fixes

We've fixed issues with Unix socket listeners, where you get internal errors or panic when running FerretDB with a Unix socket listener.
We've fixed issues with Unix domain socket listeners, where you get internal errors or panic when running FerretDB with a Unix domain socket listener.

## Other changes and enhancements

Expand Down