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
53 changes: 51 additions & 2 deletions aks-node-controller/parser/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ func getSysctlContent(s *aksnodeconfigv1.SysctlConfig) string {

m := make(map[string]interface{})
m["net.ipv4.tcp_retries2"] = defaultNetIpv4TcpRetries2
if s.NetIpv4TcpRetries2 != nil {
m["net.ipv4.tcp_retries2"] = s.GetNetIpv4TcpRetries2()
}
m["net.core.message_burst"] = defaultNetCoreMessageBurst
m["net.core.message_cost"] = defaultNetCoreMessageCost

Expand Down Expand Up @@ -416,6 +419,10 @@ func getSysctlContent(s *aksnodeconfigv1.SysctlConfig) string {
m["net.ipv4.tcp_fin_timeout"] = s.GetNetIpv4TcpFinTimeout()
}

if s.NetIpv4TcpRmem != nil {
m["net.ipv4.tcp_rmem"] = s.GetNetIpv4TcpRmem()
}

if s.NetIpv4TcpKeepaliveTime != nil {
m["net.ipv4.tcp_keepalive_time"] = s.GetNetIpv4TcpKeepaliveTime()
}
Expand All @@ -436,11 +443,23 @@ func getSysctlContent(s *aksnodeconfigv1.SysctlConfig) string {
}
}

if s.NetIpv4IpLocalReservedPorts != nil {
m["net.ipv4.ip_local_reserved_ports"] = s.GetNetIpv4IpLocalReservedPorts()
}

if s.GetNetIpv4IpLocalPortRange() != "" {
m["net.ipv4.ip_local_port_range"] = s.GetNetIpv4IpLocalPortRange()
if getPortRangeEndValue(s.GetNetIpv4IpLocalPortRange()) > ipLocalReservedPorts {
m["net.ipv4.ip_local_reserved_ports"] = ipLocalReservedPorts
}

if s.GetNetIpv4IpLocalPortRange() != "" && getPortRangeEndValue(s.GetNetIpv4IpLocalPortRange()) > ipLocalReservedPorts {
ports := s.GetNetIpv4IpLocalReservedPorts()
if !reservedPortsContain(ports, ipLocalReservedPorts) {
if ports != "" {
ports += ","
}
ports += strconv.Itoa(ipLocalReservedPorts)
}
m["net.ipv4.ip_local_reserved_ports"] = ports
}

if s.NetNetfilterNfConntrackMax != nil {
Expand All @@ -455,6 +474,10 @@ func getSysctlContent(s *aksnodeconfigv1.SysctlConfig) string {
m["fs.inotify.max_user_watches"] = s.GetFsInotifyMaxUserWatches()
}

if s.FsInotifyMaxUserInstances != nil {
m["fs.inotify.max_user_instances"] = s.GetFsInotifyMaxUserInstances()
}

if s.FsFileMax != nil {
m["fs.file-max"] = s.GetFsFileMax()
}
Expand Down Expand Up @@ -486,6 +509,32 @@ func getSysctlContent(s *aksnodeconfigv1.SysctlConfig) string {
return base64.StdEncoding.EncodeToString([]byte(createSortedKeyValuePairs(m, "\n") + "\n"))
}

func reservedPortsContain(ports string, port int) bool {
if ports == "" {
return false
}
for _, entry := range strings.Split(ports, ",") {
startText, endText, isRange := strings.Cut(strings.TrimSpace(entry), "-")
start, err := strconv.Atoi(startText)
if err != nil {
log.Printf("invalid reserved port %q: %v", entry, err)
continue
}
end := start
if isRange {
end, err = strconv.Atoi(endText)
if err != nil {
log.Printf("invalid reserved port range %q: %v", entry, err)
continue
}
}
if start <= port && port <= end {
return true
}
}
return false
}

func getShouldConfigContainerdUlimits(u *aksnodeconfigv1.UlimitConfig) bool {
return u != nil
}
Expand Down
178 changes: 178 additions & 0 deletions aks-node-controller/parser/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package parser

import (
"context"
_ "embed"
"encoding/base64"
"encoding/json"
Expand All @@ -28,8 +29,11 @@ import (

"github.com/Azure/agentbaker/aks-node-controller/helpers"
aksnodeconfigv1 "github.com/Azure/agentbaker/aks-node-controller/pkg/gen/aksnodeconfig/v1"
"github.com/Azure/agentbaker/aks-node-controller/pkg/nodeconfigutils"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)

var expectedKubeletConfigFlags = "--address=0.0.0.0" +
Expand Down Expand Up @@ -203,6 +207,180 @@ net.ipv4.tcp_retries2=8
}
}

func TestSysctlSettingsRoundTrip(t *testing.T) {
tests := []struct {
name string
json string
want map[string]string
}{
{
name: "omitted sysctl config",
json: `{}`,
},
{
name: "empty sysctl config",
json: `{"sysctlConfig": {}}`,
},
{
name: "custom settings",
json: `{"sysctlConfig": {
"fsInotifyMaxUserInstances": 2048,
"netIpv4TcpFinTimeout": 30,
"netIpv4TcpRmem": "4096 131072 6291456",
"netIpv4IpLocalReservedPorts": "30000-31000,32000",
"netIpv4TcpRetries2": 12
}}`,
want: map[string]string{
"fs.inotify.max_user_instances": "2048",
"net.ipv4.tcp_fin_timeout": "30",
"net.ipv4.tcp_rmem": "4096 131072 6291456",
"net.ipv4.ip_local_reserved_ports": "30000-31000,32000",
"net.ipv4.tcp_retries2": "12",
},
},
{
name: "explicit zero values preserve presence",
json: `{"sysctlConfig": {
"fsInotifyMaxUserInstances": 0,
"netIpv4TcpFinTimeout": 0,
"netIpv4TcpRetries2": 0
}}`,
want: map[string]string{
"fs.inotify.max_user_instances": "0",
"net.ipv4.tcp_fin_timeout": "0",
"net.ipv4.tcp_retries2": "0",
},
},
{
name: "explicit empty reservations",
json: `{"sysctlConfig": {"netIpv4IpLocalReservedPorts": ""}}`,
want: map[string]string{"net.ipv4.ip_local_reserved_ports": ""},
},
{
name: "automatic reservation unchanged",
json: `{"sysctlConfig": {"netIpv4IpLocalPortRange": "32768 65400"}}`,
want: map[string]string{
"net.ipv4.ip_local_port_range": "32768 65400",
"net.ipv4.ip_local_reserved_ports": "65330",
},
},
{
name: "customer reservations retain automatic port",
json: `{"sysctlConfig": {
"netIpv4IpLocalPortRange": "32768 65400",
"netIpv4IpLocalReservedPorts": "30000-31000,32000"
}}`,
want: map[string]string{
"net.ipv4.ip_local_port_range": "32768 65400",
"net.ipv4.ip_local_reserved_ports": "30000-31000,32000,65330",
},
},
{
name: "empty reservations retain automatic port",
json: `{"sysctlConfig": {
"netIpv4IpLocalPortRange": "32768 65400",
"netIpv4IpLocalReservedPorts": ""
}}`,
want: map[string]string{
"net.ipv4.ip_local_port_range": "32768 65400",
"net.ipv4.ip_local_reserved_ports": "65330",
},
},
{
name: "existing automatic port not duplicated",
json: `{"sysctlConfig": {
"netIpv4IpLocalPortRange": "32768 65400",
"netIpv4IpLocalReservedPorts": "32000,65330"
}}`,
want: map[string]string{
"net.ipv4.ip_local_port_range": "32768 65400",
"net.ipv4.ip_local_reserved_ports": "32000,65330",
},
},
{
name: "range covering automatic port not duplicated",
json: `{"sysctlConfig": {
"netIpv4IpLocalPortRange": "32768 65400",
"netIpv4IpLocalReservedPorts": "65300-65400"
}}`,
want: map[string]string{
"net.ipv4.ip_local_port_range": "32768 65400",
"net.ipv4.ip_local_reserved_ports": "65300-65400",
},
},
{
name: "automatic reservation threshold unchanged",
json: `{"sysctlConfig": {"netIpv4IpLocalPortRange": "32768 65330"}}`,
want: map[string]string{"net.ipv4.ip_local_port_range": "32768 65330"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
payload := []byte(`{"kubernetesVersion":"1.34.0","customLinuxOsConfig":` + test.json + `}`)
config, err := nodeconfigutils.UnmarshalConfigurationV1(payload)
require.NoError(t, err)
encoded, err := nodeconfigutils.MarshalConfigurationV1(config)
require.NoError(t, err)
restored, err := nodeconfigutils.UnmarshalConfigurationV1(encoded)
require.NoError(t, err)
require.True(t, proto.Equal(config, restored))
wire, err := proto.Marshal(restored)
require.NoError(t, err)
decoded := &aksnodeconfigv1.Configuration{}
require.NoError(t, proto.Unmarshal(wire, decoded))
require.True(t, proto.Equal(config, decoded))

command, err := BuildCSECmd(context.Background(), decoded, nil)
require.NoError(t, err)
content, err := base64.StdEncoding.DecodeString(environToMap(command.Env)["SYSCTL_CONTENT"])
require.NoError(t, err)
require.True(t, strings.HasSuffix(string(content), "\n"))
want := map[string]string{
"net.core.message_burst": "80",
"net.core.message_cost": "40",
"net.core.somaxconn": "16384",
"net.ipv4.neigh.default.gc_thresh1": "4096",
"net.ipv4.neigh.default.gc_thresh2": "8192",
"net.ipv4.neigh.default.gc_thresh3": "16384",
"net.ipv4.tcp_max_syn_backlog": "16384",
"net.ipv4.tcp_retries2": "8",
}
for key, value := range test.want {
want[key] = value
}
got := make(map[string]string)
for _, line := range strings.Split(strings.TrimSuffix(string(content), "\n"), "\n") {
key, value, ok := strings.Cut(line, "=")
require.True(t, ok, "expected key=value: %q", line)
require.NotContains(t, got, key, "duplicate sysctl key")
got[key] = value
}
require.Equal(t, want, got)
})
}
}

func TestReservedPortsContain(t *testing.T) {
for _, test := range []struct {
ports string
want bool
}{
{"", false},
{"6533", false},
{"16533", false},
{"65330", true},
{"32000,65330", true},
{"65330-65400", true},
{"65000-65330", true},
{"65000-65329", false},
{"65331-65400", false},
} {
t.Run(test.ports, func(t *testing.T) {
require.Equal(t, test.want, reservedPortsContain(test.ports, ipLocalReservedPorts))
})
}
}

func Test_getUlimitContent(t *testing.T) {
type args struct {
u *aksnodeconfigv1.UlimitConfig
Expand Down
Loading
Loading