Skip to content
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
4 changes: 3 additions & 1 deletion cmd/lattice-agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,9 @@ func monitorChanged(a, b model.Monitor) bool {
return a.Type != b.Type || a.Target != b.Target || a.TargetNode != b.TargetNode ||
a.IntervalSec != b.IntervalSec || a.TimeoutSec != b.TimeoutSec ||
a.Packets != b.Packets || a.ExpectStatus != b.ExpectStatus ||
a.SecretsOrigin != b.SecretsOrigin || !slices.Equal(a.Headers, b.Headers)
a.SecretsOrigin != b.SecretsOrigin || !slices.Equal(a.Headers, b.Headers) ||
a.DNSName != b.DNSName || a.DNSType != b.DNSType || a.DNSExpectRcode != b.DNSExpectRcode ||
!slices.Equal(a.DNSExpect, b.DNSExpect)
}

// probe runs one probe and queues its result; flushLoop sends it, in a batch
Expand Down
10 changes: 7 additions & 3 deletions cmd/lattice-agent/probe_facts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestHelloAndHeartbeatCarryProbeFacts(t *testing.T) {
if err := json.Unmarshal(data, &got); err != nil {
t.Fatal(err)
}
for _, kind := range []string{model.MonitorTypeTCP, model.MonitorTypeHTTP} {
for _, kind := range []string{model.MonitorTypeTCP, model.MonitorTypeHTTP, model.MonitorTypeDNS, model.MonitorTypeBeacon} {
if !slices.Contains(got.ProbeMethods, kind) {
t.Fatalf("%s probe_methods %v lacks %s", name, got.ProbeMethods, kind)
}
Expand All @@ -70,8 +70,12 @@ func TestMonitorChangedCoversProbeFields(t *testing.T) {
"header value": func(m *model.Monitor) {
m.Headers = []model.MonitorHeader{{Name: "X-Api-Key", Value: "two", Secret: true}}
},
"header removed": func(m *model.Monitor) { m.Headers = nil },
"secrets_origin": func(m *model.Monitor) { m.SecretsOrigin = "https://b.example:443" },
"header removed": func(m *model.Monitor) { m.Headers = nil },
"secrets_origin": func(m *model.Monitor) { m.SecretsOrigin = "https://b.example:443" },
"dns_name": func(m *model.Monitor) { m.DNSName = "example.net" },
"dns_type": func(m *model.Monitor) { m.DNSType = model.DNSTypeAAAA },
"dns_expect": func(m *model.Monitor) { m.DNSExpect = []string{"192.0.2.1"} },
"dns_expect_rcode": func(m *model.Monitor) { m.DNSExpectRcode = model.DNSRcodeNXDomain },
} {
changed := base
changed.Headers = slices.Clone(base.Headers)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.26.0

toolchain go1.26.10

require github.com/LatticeNet/lattice-sdk v0.2.24-0.20261017194014-a3de5f71b589
require github.com/LatticeNet/lattice-sdk v0.2.24-0.20261025003326-6485e4abe7b9

require github.com/creack/pty v1.1.24

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/LatticeNet/lattice-sdk v0.2.24-0.20261017194014-a3de5f71b589 h1:B7EVUKUz5Bj9gKIt7H7n3YJfTBR0nGz5op6qMnoZEJE=
github.com/LatticeNet/lattice-sdk v0.2.24-0.20261017194014-a3de5f71b589/go.mod h1:jx9PFwMH2zT993VRwecQZBo/rP9W1lgWcZYDdqr5D9M=
github.com/LatticeNet/lattice-sdk v0.2.24-0.20261025003326-6485e4abe7b9 h1:aKA/XfkcXfbYbGKSETmqwAUDVJ+EZMC68Oy8TMDgnG8=
github.com/LatticeNet/lattice-sdk v0.2.24-0.20261025003326-6485e4abe7b9/go.mod h1:jx9PFwMH2zT993VRwecQZBo/rP9W1lgWcZYDdqr5D9M=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
Expand Down
40 changes: 24 additions & 16 deletions internal/prober/destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,27 +83,35 @@ func asciiHost(host string) (string, error) {
// net.Dialer gives each address of a serial fallback.
const minDialSlice = 2 * time.Second

// dialJudged connects to the first of addrs that answers on port, in the
// order the resolver gave them, sharing the time left between the
// addresses not yet tried as net.Dialer does. addrs are IP literals, so the
// dial makes no lookup.
func (p *prober) dialJudged(ctx context.Context, addrs []netip.Addr, port string) (net.Conn, error) {
// addrContext is the share of ctx's time one address gets while left
// addresses, itself included, remain to be tried: an equal share of what is
// left, at least minDialSlice (or all of it when less remains), and all of
// it for the last address.
func addrContext(ctx context.Context, left int) (context.Context, context.CancelFunc) {
if left > 1 {
if deadline, ok := ctx.Deadline(); ok {
slice := time.Until(deadline) / time.Duration(left)
if slice < minDialSlice {
slice = min(minDialSlice, time.Until(deadline))
}
return context.WithTimeout(ctx, slice)
}
}
return ctx, func() {}
}

// dialJudged connects over network (tcp or udp) to the first of addrs that
// answers on port, in the order the resolver gave them, sharing the time
// left between the addresses not yet tried as net.Dialer does. addrs are
// IP literals, so the dial makes no lookup.
func (p *prober) dialJudged(ctx context.Context, network string, addrs []netip.Addr, port string) (net.Conn, error) {
if len(addrs) == 0 {
return nil, errors.New("no address to dial")
}
var firstErr error
for i, addr := range addrs {
dctx, cancel := ctx, context.CancelFunc(func() {})
if left := len(addrs) - i; left > 1 {
if deadline, ok := ctx.Deadline(); ok {
slice := time.Until(deadline) / time.Duration(left)
if slice < minDialSlice {
slice = min(minDialSlice, time.Until(deadline))
}
dctx, cancel = context.WithTimeout(ctx, slice)
}
}
conn, err := p.dial(dctx, "tcp", net.JoinHostPort(addr.String(), port))
dctx, cancel := addrContext(ctx, len(addrs)-i)
conn, err := p.dial(dctx, network, net.JoinHostPort(addr.String(), port))
cancel()
if err == nil {
return conn, nil
Expand Down
Loading
Loading