Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat!: add interface report to coder netcheck#13562

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
spikecurtis merged 1 commit intomainfromspike/netcheck-interface-report
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes fromall 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
15 changes: 13 additions & 2 deletionscli/netcheck.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,6 +10,7 @@ import (

"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/healthsdk"
"github.com/coder/coder/v2/codersdk/workspacesdk"
"github.com/coder/serpent"
)
Expand All@@ -34,11 +35,21 @@ func (r *RootCmd) netcheck() *serpent.Command {

_, _ = fmt.Fprint(inv.Stderr, "Gathering a network report. This may take a few seconds...\n\n")

varreport derphealth.Report
report.Run(ctx, &derphealth.ReportOptions{
varderpReport derphealth.Report
derpReport.Run(ctx, &derphealth.ReportOptions{
DERPMap: connInfo.DERPMap,
})

ifReport, err := healthsdk.RunInterfacesReport()
if err != nil {
return xerrors.Errorf("failed to run interfaces report: %w", err)
}

report := healthsdk.ClientNetcheckReport{
DERP: healthsdk.DERPHealthReport(derpReport),
Interfaces: ifReport,
}

raw, err := json.MarshalIndent(report, "", " ")
if err != nil {
return err
Expand Down
6 changes: 3 additions & 3 deletionscli/netcheck_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,13 +26,13 @@ func TestNetcheck(t *testing.T) {

b := out.Bytes()
t.Log(string(b))
var report healthsdk.DERPHealthReport
var report healthsdk.ClientNetcheckReport
require.NoError(t, json.Unmarshal(b, &report))

// We do not assert that the report is healthy, just that
// it has the expected number of reports per region.
require.Len(t, report.Regions, 1+1) // 1 built-in region + 1 test-managed STUN region
for _, v := range report.Regions {
require.Len(t, report.DERP.Regions, 1+1) // 1 built-in region + 1 test-managed STUN region
for _, v := range report.DERP.Regions {
require.Len(t, v.NodeReports, len(v.Region.Nodes))
}
}
2 changes: 2 additions & 0 deletionscoderd/healthcheck/health/model.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,6 +43,8 @@ const (
CodeProvisionerDaemonsNoProvisionerDaemons Code = `EPD01`
CodeProvisionerDaemonVersionMismatch Code = `EPD02`
CodeProvisionerDaemonAPIMajorVersionDeprecated Code = `EPD03`

CodeInterfaceSmallMTU = `EIF01`
)

// Default docs URL
Expand Down
6 changes: 6 additions & 0 deletionscodersdk/healthsdk/healthsdk.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -269,3 +269,9 @@ type WorkspaceProxyReport struct {
BaseReport
WorkspaceProxies codersdk.RegionsResponse[codersdk.WorkspaceProxy] `json:"workspace_proxies"`
}

// @typescript-ignore ClientNetcheckReport
type ClientNetcheckReport struct {
DERP DERPHealthReport `json:"derp"`
Interfaces InterfacesReport `json:"interfaces"`
}
73 changes: 73 additions & 0 deletionscodersdk/healthsdk/interfaces.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
package healthsdk

import (
"net"

"tailscale.com/net/interfaces"

"github.com/coder/coder/v2/coderd/healthcheck/health"
)

// @typescript-ignore InterfacesReport
type InterfacesReport struct {
BaseReport
Interfaces []Interface `json:"interfaces"`
}

// @typescript-ignore Interface
type Interface struct {
Name string `json:"name"`
MTU int `json:"mtu"`
Addresses []string `json:"addresses"`
}

func RunInterfacesReport() (InterfacesReport, error) {
st, err := interfaces.GetState()
if err != nil {
return InterfacesReport{}, err
}
return generateInterfacesReport(st), nil
}

func generateInterfacesReport(st *interfaces.State) (report InterfacesReport) {
report.Severity = health.SeverityOK
for name, iface := range st.Interface {
// macOS has a ton of random interfaces, so to keep things helpful, let's filter out any
// that:
//
// - are not enabled
// - don't have any addresses
// - have only link-local addresses (e.g. fe80:...)
if (iface.Flags & net.FlagUp) == 0 {
continue
}
addrs := st.InterfaceIPs[name]
if len(addrs) == 0 {
continue
}
var r bool
healthIface := Interface{
Name: iface.Name,
MTU: iface.MTU,
}
for _, addr := range addrs {
healthIface.Addresses = append(healthIface.Addresses, addr.String())
if addr.Addr().IsLinkLocalUnicast() || addr.Addr().IsLinkLocalMulticast() {
continue
}
r = true
}
if !r {
continue
}
report.Interfaces = append(report.Interfaces, healthIface)
if iface.MTU < 1378 {
report.Severity = health.SeverityWarning
report.Warnings = append(report.Warnings,
health.Messagef(health.CodeInterfaceSmallMTU,
"network interface %s has MTU %d (less than 1378), which may cause problems with direct connections", iface.Name, iface.MTU),
)
}
}
return report
}
192 changes: 192 additions & 0 deletionscodersdk/healthsdk/interfaces_internal_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
package healthsdk

import (
"net"
"net/netip"
"strings"
"testing"

"github.com/stretchr/testify/require"
"golang.org/x/exp/slices"
"tailscale.com/net/interfaces"

"github.com/coder/coder/v2/coderd/healthcheck/health"
)

func Test_generateInterfacesReport(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
state interfaces.State
severity health.Severity
expectedInterfaces []string
expectedWarnings []string
}{
{
name: "Empty",
state: interfaces.State{},
severity: health.SeverityOK,
expectedInterfaces: []string{},
},
{
name: "Normal",
state: interfaces.State{
Interface: map[string]interfaces.Interface{
"en0": {Interface: &net.Interface{
MTU: 1500,
Name: "en0",
Flags: net.FlagUp,
}},
"lo0": {Interface: &net.Interface{
MTU: 65535,
Name: "lo0",
Flags: net.FlagUp,
}},
},
InterfaceIPs: map[string][]netip.Prefix{
"en0": {
netip.MustParsePrefix("192.168.100.1/24"),
netip.MustParsePrefix("fe80::c13:1a92:3fa5:dd7e/64"),
},
"lo0": {
netip.MustParsePrefix("127.0.0.1/8"),
netip.MustParsePrefix("::1/128"),
netip.MustParsePrefix("fe80::1/64"),
},
},
},
severity: health.SeverityOK,
expectedInterfaces: []string{"en0", "lo0"},
},
{
name: "IgnoreDisabled",
state: interfaces.State{
Interface: map[string]interfaces.Interface{
"en0": {Interface: &net.Interface{
MTU: 1300,
Name: "en0",
Flags: 0,
}},
"lo0": {Interface: &net.Interface{
MTU: 65535,
Name: "lo0",
Flags: net.FlagUp,
}},
},
InterfaceIPs: map[string][]netip.Prefix{
"en0": {netip.MustParsePrefix("192.168.100.1/24")},
"lo0": {netip.MustParsePrefix("127.0.0.1/8")},
},
},
severity: health.SeverityOK,
expectedInterfaces: []string{"lo0"},
},
{
name: "IgnoreLinkLocalOnly",
state: interfaces.State{
Interface: map[string]interfaces.Interface{
"en0": {Interface: &net.Interface{
MTU: 1300,
Name: "en0",
Flags: net.FlagUp,
}},
"lo0": {Interface: &net.Interface{
MTU: 65535,
Name: "lo0",
Flags: net.FlagUp,
}},
},
InterfaceIPs: map[string][]netip.Prefix{
"en0": {netip.MustParsePrefix("fe80::1:1/64")},
"lo0": {netip.MustParsePrefix("127.0.0.1/8")},
},
},
severity: health.SeverityOK,
expectedInterfaces: []string{"lo0"},
},
{
name: "IgnoreNoAddress",
state: interfaces.State{
Interface: map[string]interfaces.Interface{
"en0": {Interface: &net.Interface{
MTU: 1300,
Name: "en0",
Flags: net.FlagUp,
}},
"lo0": {Interface: &net.Interface{
MTU: 65535,
Name: "lo0",
Flags: net.FlagUp,
}},
},
InterfaceIPs: map[string][]netip.Prefix{
"en0": {},
"lo0": {netip.MustParsePrefix("127.0.0.1/8")},
},
},
severity: health.SeverityOK,
expectedInterfaces: []string{"lo0"},
},
{
name: "SmallMTUTunnel",
state: interfaces.State{
Interface: map[string]interfaces.Interface{
"en0": {Interface: &net.Interface{
MTU: 1500,
Name: "en0",
Flags: net.FlagUp,
}},
"lo0": {Interface: &net.Interface{
MTU: 65535,
Name: "lo0",
Flags: net.FlagUp,
}},
"tun0": {Interface: &net.Interface{
MTU: 1280,
Name: "tun0",
Flags: net.FlagUp,
}},
},
InterfaceIPs: map[string][]netip.Prefix{
"en0": {netip.MustParsePrefix("192.168.100.1/24")},
"tun0": {netip.MustParsePrefix("10.3.55.9/8")},
"lo0": {netip.MustParsePrefix("127.0.0.1/8")},
},
},
severity: health.SeverityWarning,
expectedInterfaces: []string{"en0", "lo0", "tun0"},
expectedWarnings: []string{"tun0"},
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
r := generateInterfacesReport(&tc.state)
require.Equal(t, tc.severity, r.Severity)
gotInterfaces := []string{}
for _, i := range r.Interfaces {
gotInterfaces = append(gotInterfaces, i.Name)
}
slices.Sort(gotInterfaces)
slices.Sort(tc.expectedInterfaces)
require.Equal(t, tc.expectedInterfaces, gotInterfaces)

require.Len(t, r.Warnings, len(tc.expectedWarnings),
"expected %d warnings, got %d", len(tc.expectedWarnings), len(r.Warnings))
for _, name := range tc.expectedWarnings {
found := false
for _, w := range r.Warnings {
if strings.Contains(w.String(), name) {
found = true
break
}
}
if !found {
t.Errorf("missing warning for %s", name)
}
}
})
}
}
11 changes: 11 additions & 0 deletionsdocs/admin/healthcheck.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -328,6 +328,17 @@ version of Coder.
> Note: This may be a transient issue if you are currently in the process of
> updating your deployment.

### EIF01

_Interface with Small MTU_

**Problem:** One or more local interfaces have MTU smaller than 1378, which is
the minimum MTU for Coder to establish direct connections without fragmentation.

**Solution:** Since IP fragmentation can be a source of performance problems, we
recommend you disable the interface when using Coder or
[disable direct connections](../../cli#--disable-direct-connections)

## EUNKNOWN

_Unknown Error_
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp