From f2ae9cd0c1b7d27b5b9971f4820e5feae7934124 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Jun 2021 01:05:41 +0300 Subject: [PATCH] feat: replace networkd with new network implementation This removes networkd, updates network ready condition, enables all the controllers which were previously disabled. Signed-off-by: Andrey Smirnov --- Dockerfile | 1 + go.mod | 20 +- go.sum | 56 -- hack/release.toml | 2 +- .../pkg/controllers/files/etcfile_test.go | 11 + .../pkg/controllers/k8s/extra_manifest.go | 16 +- .../controllers/k8s/extra_manifest_test.go | 9 +- .../pkg/controllers/network/address_config.go | 9 +- .../network/address_config_test.go | 19 + .../pkg/controllers/network/address_merge.go | 2 + .../controllers/network/address_merge_test.go | 11 + .../pkg/controllers/network/address_spec.go | 9 +- .../controllers/network/address_spec_test.go | 18 +- .../network/address_status_test.go | 8 + .../pkg/controllers/network/etcfile_test.go | 23 + .../network/hostname_config_test.go | 21 + .../network/hostname_merge_test.go | 13 + .../pkg/controllers/network/hostname_spec.go | 2 + .../controllers/network/hostname_spec_test.go | 11 + .../controllers/network/link_config_test.go | 21 + .../controllers/network/link_merge_test.go | 11 + .../pkg/controllers/network/link_spec_test.go | 11 + .../controllers/network/link_status_test.go | 18 +- .../controllers/network/node_address_test.go | 12 + .../pkg/controllers/network/operator/dhcp4.go | 26 +- .../network/operator_config_test.go | 21 + .../network/platform_config_test.go | 203 ++++++++ .../network/resolver_config_test.go | 19 + .../network/resolver_merge_test.go | 11 + .../controllers/network/resolver_spec_test.go | 11 + .../pkg/controllers/network/route_config.go | 25 +- .../controllers/network/route_config_test.go | 33 +- .../pkg/controllers/network/route_merge.go | 2 + .../controllers/network/route_merge_test.go | 29 +- .../pkg/controllers/network/route_spec.go | 36 +- .../controllers/network/route_spec_test.go | 140 +++++ .../controllers/network/route_status_test.go | 10 +- .../pkg/controllers/network/status_test.go | 14 + .../network/timeserver_config_test.go | 19 + .../network/timeserver_merge_test.go | 11 + .../network/timeserver_spec_test.go | 11 + .../machined/pkg/controllers/secrets/etcd.go | 15 +- .../pkg/controllers/secrets/kubernetes.go | 77 +-- .../v1alpha1/platform/packet/packet.go | 4 +- .../runtime/v1alpha1/v1alpha1_sequencer.go | 18 - .../v1alpha1/v1alpha1_sequencer_tasks.go | 62 --- .../runtime/v1alpha2/v1alpha2_controller.go | 20 +- .../app/machined/pkg/system/services/apid.go | 4 +- .../app/machined/pkg/system/services/cri.go | 5 +- .../app/machined/pkg/system/services/etcd.go | 8 +- .../machined/pkg/system/services/kubelet.go | 8 +- .../machined/pkg/system/services/networkd.go | 123 ----- .../pkg/system/services/networkd_test.go | 18 - .../machined/pkg/system/services/trustd.go | 8 +- internal/app/networkd/main.go | 79 --- internal/app/networkd/pkg/address/address.go | 49 -- internal/app/networkd/pkg/address/dhcp4.go | 273 ---------- internal/app/networkd/pkg/address/dhcp6.go | 203 -------- internal/app/networkd/pkg/address/static.go | 145 ------ internal/app/networkd/pkg/networkd/misc.go | 154 ------ internal/app/networkd/pkg/networkd/netconf.go | 323 ------------ .../app/networkd/pkg/networkd/netconf_test.go | 147 ------ .../app/networkd/pkg/networkd/networkd.go | 468 ----------------- .../networkd/pkg/networkd/networkd_test.go | 213 -------- internal/app/networkd/pkg/nic/bond_options.go | 373 -------------- internal/app/networkd/pkg/nic/netlink.go | 152 ------ internal/app/networkd/pkg/nic/nic.go | 486 ------------------ internal/app/networkd/pkg/nic/nic_test.go | 128 ----- internal/app/networkd/pkg/nic/options.go | 71 --- internal/app/networkd/pkg/nic/vars.go | 322 ------------ internal/app/networkd/pkg/nic/vip_options.go | 29 -- internal/app/networkd/pkg/nic/vlan_options.go | 75 --- internal/app/networkd/pkg/nic/wireguard.go | 87 ---- internal/app/networkd/pkg/reg/reg.go | 102 ---- internal/app/networkd/pkg/reg/reg_test.go | 109 ---- internal/app/networkd/pkg/server/server.go | 1 - internal/app/networkd/pkg/vip/vip.go | 197 ------- pkg/resources/k8s/static_pod_status.go | 5 + pkg/resources/network/network.go | 2 +- pkg/resources/network/route_spec.go | 35 ++ 80 files changed, 965 insertions(+), 4588 deletions(-) create mode 100644 internal/app/machined/pkg/controllers/network/platform_config_test.go delete mode 100644 internal/app/machined/pkg/system/services/networkd.go delete mode 100644 internal/app/machined/pkg/system/services/networkd_test.go delete mode 100644 internal/app/networkd/main.go delete mode 100644 internal/app/networkd/pkg/address/address.go delete mode 100644 internal/app/networkd/pkg/address/dhcp4.go delete mode 100644 internal/app/networkd/pkg/address/dhcp6.go delete mode 100644 internal/app/networkd/pkg/address/static.go delete mode 100644 internal/app/networkd/pkg/networkd/misc.go delete mode 100644 internal/app/networkd/pkg/networkd/netconf.go delete mode 100644 internal/app/networkd/pkg/networkd/netconf_test.go delete mode 100644 internal/app/networkd/pkg/networkd/networkd.go delete mode 100644 internal/app/networkd/pkg/networkd/networkd_test.go delete mode 100644 internal/app/networkd/pkg/nic/bond_options.go delete mode 100644 internal/app/networkd/pkg/nic/netlink.go delete mode 100644 internal/app/networkd/pkg/nic/nic.go delete mode 100644 internal/app/networkd/pkg/nic/nic_test.go delete mode 100644 internal/app/networkd/pkg/nic/options.go delete mode 100644 internal/app/networkd/pkg/nic/vars.go delete mode 100644 internal/app/networkd/pkg/nic/vip_options.go delete mode 100644 internal/app/networkd/pkg/nic/vlan_options.go delete mode 100644 internal/app/networkd/pkg/nic/wireguard.go delete mode 100644 internal/app/networkd/pkg/reg/reg.go delete mode 100644 internal/app/networkd/pkg/reg/reg_test.go delete mode 100644 internal/app/networkd/pkg/vip/vip.go diff --git a/Dockerfile b/Dockerfile index 3747fdcd7..922b08a97 100644 --- a/Dockerfile +++ b/Dockerfile @@ -180,6 +180,7 @@ COPY --from=generate-build /api/cluster/*.pb.go /pkg/machinery/api/cluster/ COPY --from=generate-build /api/storage/*.pb.go /pkg/machinery/api/storage/ COPY --from=generate-build /api/resource/*.pb.go /pkg/machinery/api/resource/ COPY --from=generate-build /api/inspect/*.pb.go /pkg/machinery/api/inspect/ +COPY --from=go-generate /src/pkg/resources/network/ /pkg/resources/network/ COPY --from=go-generate /src/pkg/machinery/config/types/v1alpha1/ /pkg/machinery/config/types/v1alpha1/ COPY --from=go-generate /src/pkg/machinery/nethelpers/ /pkg/machinery/nethelpers/ diff --git a/go.mod b/go.mod index 5e6848f5a..c1645976f 100644 --- a/go.mod +++ b/go.mod @@ -44,27 +44,39 @@ require ( github.com/gizak/termui/v3 v3.1.0 github.com/golang/protobuf v1.5.2 github.com/google/go-cmp v0.5.6 + github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.2.0 + github.com/googleapis/gnostic v0.5.5 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/hashicorp/go-getter v1.5.3 github.com/hashicorp/go-multierror v1.1.1 + github.com/imdario/mergo v0.3.12 // indirect github.com/insomniacslk/dhcp v0.0.0-20210528123148-fb4eaaa00ad2 github.com/jsimonetti/rtnetlink v0.0.0-20210531051304-b34cb89a106b + github.com/magiconair/properties v1.8.5 // indirect github.com/mattn/go-isatty v0.0.13 github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 github.com/mdlayher/genetlink v1.0.0 github.com/mdlayher/netlink v1.4.1 + github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d + github.com/pelletier/go-toml v1.9.0 // indirect github.com/pin/tftp v2.1.0+incompatible - github.com/plunder-app/kube-vip v0.3.5 + github.com/prometheus/client_golang v1.10.0 // indirect + github.com/prometheus/common v0.23.0 // indirect github.com/prometheus/procfs v0.6.0 github.com/rivo/tview v0.0.0-20210531104647-807e706f86d1 github.com/rs/xid v1.3.0 github.com/ryanuber/columnize v2.1.2+incompatible + github.com/sirupsen/logrus v1.8.1 // indirect github.com/smira/go-xz v0.0.0-20201019130106-9921ed7a9935 + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.1.3 + github.com/spf13/viper v1.7.1 // indirect github.com/stretchr/testify v1.7.0 github.com/talos-systems/crypto v0.2.1-0.20210601174604-cd18ef62eb9f github.com/talos-systems/go-blockdevice v0.2.1-0.20210526155905-30c2bc3cb62a @@ -79,6 +91,7 @@ require ( github.com/talos-systems/net v0.2.1-0.20210212213224-05190541b0fa github.com/talos-systems/talos/pkg/machinery v0.0.0-00010101000000-000000000000 github.com/u-root/u-root v7.0.0+incompatible + github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect github.com/vmware-tanzu/sonobuoy v0.50.0 github.com/vmware/govmomi v0.26.0 github.com/vmware/vmw-guestinfo v0.0.0-20200218095840-687661b8bd8e @@ -88,14 +101,17 @@ require ( go.etcd.io/etcd/etcdutl/v3 v3.5.0-rc.0 go.uber.org/zap v1.17.0 golang.org/x/net v0.0.0-20210525063256-abc453219eb5 + golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549 golang.org/x/term v0.0.0-20210503060354-a79de5458b56 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5 + google.golang.org/appengine v1.6.7 // indirect google.golang.org/grpc v1.38.0 google.golang.org/protobuf v1.26.0 gopkg.in/freddierice/go-losetup.v1 v1.0.0-20170407175016-fc9adea44124 + gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b inet.af/netaddr v0.0.0-20210430201628-1d252cf8125e k8s.io/api v0.21.1 @@ -105,4 +121,6 @@ require ( k8s.io/cri-api v0.21.1 k8s.io/kubectl v0.21.1 k8s.io/kubelet v0.21.1 + k8s.io/utils v0.0.0-20210305010621-2afb4311ab10 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.1 // indirect ) diff --git a/go.sum b/go.sum index 35bdd3d27..a3949bff2 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,6 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= @@ -119,7 +117,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alessio/shellescape v1.2.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -130,8 +127,6 @@ github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloD github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= -github.com/armon/go-metrics v0.3.8/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -197,8 +192,6 @@ github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJ github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.6.0 h1:hOQqNhQdMIi0zmjii4jKUnI0i+NB7ApvTXs2MstI5S0= github.com/cilium/ebpf v0.6.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -351,7 +344,6 @@ github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1 github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= @@ -406,13 +398,11 @@ github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/firecracker-microvm/firecracker-go-sdk v0.22.0 h1:hk28AO5ArAX9iHomi6axNLK+6+8gz1wi3ooNsUTlSFQ= @@ -640,8 +630,6 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs= @@ -700,27 +688,21 @@ github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyN github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-getter v1.5.3 h1:NF5+zOlQegim+w/EUhSLh6QhXHmZMEeHLQzllkQ3ROU= github.com/hashicorp/go-getter v1.5.3/go.mod h1:BrrV/1clo8cCYu6mxvboYg+KutTiFnXjMEgDD8+i7ZI= -github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.16.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.0 h1:8exGP7ego3OmkfksihtSouGMZ+hQrhxx+FVELeXpVPE= github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-memdb v1.3.2 h1:RBKHOsnSszpU6vxq80LzC2BaQjuuvoyaQbkLTf7V7g8= github.com/hashicorp/go-memdb v1.3.2/go.mod h1:Mluclgwib3R93Hk5fxEfiRhB+6Dar64wWh71LpNSe3g= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= @@ -742,7 +724,6 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/raft v1.3.1/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= @@ -762,7 +743,6 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod github.com/insomniacslk/dhcp v0.0.0-20210528123148-fb4eaaa00ad2 h1:WDOgJoE6rb7G6A7i1/Yyh5FJeydXeUrXHMRYJo7iFak= github.com/insomniacslk/dhcp v0.0.0-20210528123148-fb4eaaa00ad2/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= @@ -773,7 +753,6 @@ github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9q github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= @@ -800,8 +779,6 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= -github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08/go.mod h1:0L/S1RSG4wA4M2Vhau3z7VsYMLxFnsX0bzzgwYRIdYU= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -856,13 +833,11 @@ github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kN github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -885,8 +860,6 @@ github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JA github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= -github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 h1:x+xs91ZJ+lr0C6sedWeREvck4uGCt+AA1kKXwsHB6jI= -github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= @@ -1026,11 +999,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/osrg/gobgp v2.0.0+incompatible/go.mod h1:vGVJPLW6JFDD7WA1vJsjB8OKmbbC2TKwHtr90CZS/u4= -github.com/packethost/packngo v0.13.0/go.mod h1:YrtUNN9IRjjqN6zK+cy2IYoi3EjHfoWTWxJkI1I1Vk0= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= @@ -1051,21 +1021,17 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/plunder-app/kube-vip v0.3.5 h1:+i4TLCWbFNNj8RHfF6BHAReOI0NCxxUAGhX4/ZdlA34= -github.com/plunder-app/kube-vip v0.3.5/go.mod h1:lN0PiOK6uwByLTLLSM45En/VOycZz3/8wQ/UQl7Qu3E= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg= @@ -1080,7 +1046,6 @@ github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -1093,7 +1058,6 @@ github.com/prometheus/common v0.23.0 h1:GXWvPYuTUenIa+BhOq/x+L/QZzCqASkVRny5KTlP github.com/prometheus/common v0.23.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -1122,8 +1086,6 @@ github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5 h1:/kzTBQ20DbbhSNaBXiFEk2gPrGhY26kajwC1ro/Vlh8= -github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5/go.mod h1:FwstIpm6vX98QgtR8KEwZcVjiRn2WP76LjXAHj84fK0= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= @@ -1256,7 +1218,6 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/u-root/u-root v7.0.0+incompatible h1:u+KSS04pSxJGI5E7WE4Bs9+Zd75QjFv+REkjy/aoAc8= github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= @@ -1276,7 +1237,6 @@ github.com/viniciuschiele/tarx v0.0.0-20151205142357-6e3da540444d h1:Z8Bp/K+wf1+ github.com/viniciuschiele/tarx v0.0.0-20151205142357-6e3da540444d/go.mod h1:8uo3DXfN526YN7JjAp4JkOMm4foTW4vPzPHaAzb4xiY= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066/go.mod h1:FSQhuTO7eHT34mPzX+B04SUAjiqLxtXs1et0S6l9k4k= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 h1:cPXZWzzG0NllBLdjWoD1nDfaqu98YMv+OneaKc8sPOA= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= @@ -1312,8 +1272,6 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= -gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI= -gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -1414,7 +1372,6 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1518,7 +1475,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210505214959-0714010a04ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1596,7 +1552,6 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200121082415-34d275377bf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1610,7 +1565,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1622,7 +1576,6 @@ golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200928205150-006507a75852/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1694,7 +1647,6 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1821,7 +1773,6 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210524171403-669157292da3/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= @@ -1925,15 +1876,12 @@ k8s.io/api v0.18.5/go.mod h1:tN+e/2nbdGKOAH55NMV8oGrMG+3uRlA9GaRfvnCCSNk= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= -k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= k8s.io/api v0.21.1 h1:94bbZ5NTjdINJEdzOkpS4vdPhkb1VFpTYC9zh43f75c= k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s= k8s.io/apimachinery v0.18.5/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= -k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= -k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= k8s.io/apimachinery v0.21.1 h1:Q6XuHGlj2xc+hlMCvqyYfbv3H7SRGn2c8NycxJquDVs= k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= @@ -1947,7 +1895,6 @@ k8s.io/client-go v0.18.5/go.mod h1:EsiD+7Fx+bRckKWZXnAXRKKetm1WuzPagH4iOSC8x58= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= -k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= k8s.io/client-go v0.21.1 h1:bhblWYLZKUu+pm50plvQF8WpY6TXdRRtcS/K9WauOj4= k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs= k8s.io/code-generator v0.21.1/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= @@ -1976,7 +1923,6 @@ k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= @@ -1995,7 +1941,6 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/kind v0.10.0/go.mod h1:fb32zUw7ewC47bPwLnwhf47wd/vADtv3c38KP7sjIlo= sigs.k8s.io/kustomize/api v0.8.8 h1:G2z6JPSSjtWWgMeWSoHdXqyftJNmMmyxXpwENGoOtGE= sigs.k8s.io/kustomize/api v0.8.8/go.mod h1:He1zoK0nk43Pc6NlV085xDXDXTNprtcyKZVm3swsdNY= sigs.k8s.io/kustomize/cmd/config v0.9.10/go.mod h1:Mrby0WnRH7hA6OwOYnYpfpiY0WJIMgYrEDfwOeFdMK0= @@ -2004,7 +1949,6 @@ sigs.k8s.io/kustomize/kyaml v0.10.17 h1:4zrV0ym5AYa0e512q7K3Wp1u7mzoWW0xR3UHJcGW sigs.k8s.io/kustomize/kyaml v0.10.17/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= diff --git a/hack/release.toml b/hack/release.toml index 9961c4424..4595ce9ef 100644 --- a/hack/release.toml +++ b/hack/release.toml @@ -46,7 +46,7 @@ Added the flag `cluster.coreDNS.disabled` to coreDNS deployment during the clust title = "Default to Bootstrap workflow" description = """\ The `init.yaml` is no longer an output of `talosctl gen config`. -We now encourage using the bootstrap API, instead it `init` node types, as we +We now encourage using the bootstrap API, instead of `init` node types, as we intend on deprecating this machine type in the future. The `init.yaml` and `controlplane.yaml` machine configs are identical with the exception of the machine type. diff --git a/internal/app/machined/pkg/controllers/files/etcfile_test.go b/internal/app/machined/pkg/controllers/files/etcfile_test.go index 682ad9e0c..fac5e957e 100644 --- a/internal/app/machined/pkg/controllers/files/etcfile_test.go +++ b/internal/app/machined/pkg/controllers/files/etcfile_test.go @@ -137,6 +137,17 @@ func (suite *EtcFileSuite) TestFiles() { } } +func (suite *EtcFileSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), files.NewEtcFileSpec(files.NamespaceName, "bar"))) +} + func TestEtcFileSuite(t *testing.T) { suite.Run(t, new(EtcFileSuite)) } diff --git a/internal/app/machined/pkg/controllers/k8s/extra_manifest.go b/internal/app/machined/pkg/controllers/k8s/extra_manifest.go index 4a267a3a6..e11cf3184 100644 --- a/internal/app/machined/pkg/controllers/k8s/extra_manifest.go +++ b/internal/app/machined/pkg/controllers/k8s/extra_manifest.go @@ -22,7 +22,7 @@ import ( "github.com/talos-systems/talos/pkg/resources/config" "github.com/talos-systems/talos/pkg/resources/k8s" - "github.com/talos-systems/talos/pkg/resources/v1alpha1" + "github.com/talos-systems/talos/pkg/resources/network" ) // ExtraManifestController renders manifests based on templates and config/secrets. @@ -43,9 +43,9 @@ func (ctrl *ExtraManifestController) Inputs() []controller.Input { Kind: controller.InputWeak, }, { - Namespace: v1alpha1.NamespaceName, - Type: v1alpha1.ServiceType, - ID: pointer.ToString("networkd"), + Namespace: network.NamespaceName, + Type: network.StatusType, + ID: pointer.ToString(network.StatusID), Kind: controller.InputWeak, }, } @@ -72,8 +72,8 @@ func (ctrl *ExtraManifestController) Run(ctx context.Context, r controller.Runti case <-r.EventCh(): } - // wait for networkd to be healthy as networking is required to download extra manifests - networkdResource, err := r.Get(ctx, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, "networkd", resource.VersionUndefined)) + // wait for network to be ready as networking is required to download extra manifests + networkResource, err := r.Get(ctx, resource.NewMetadata(network.NamespaceName, network.StatusType, network.StatusID, resource.VersionUndefined)) if err != nil { if state.IsNotFoundError(err) { continue @@ -82,7 +82,9 @@ func (ctrl *ExtraManifestController) Run(ctx context.Context, r controller.Runti return err } - if !networkdResource.(*v1alpha1.Service).Healthy() { + networkStatus := networkResource.(*network.Status).TypedSpec() + + if !(networkStatus.AddressReady && networkStatus.ConnectivityReady) { continue } diff --git a/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go b/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go index 90c308f41..a825a1908 100644 --- a/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go +++ b/internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go @@ -26,6 +26,7 @@ import ( "github.com/talos-systems/talos/pkg/logging" "github.com/talos-systems/talos/pkg/resources/config" "github.com/talos-systems/talos/pkg/resources/k8s" + "github.com/talos-systems/talos/pkg/resources/network" "github.com/talos-systems/talos/pkg/resources/v1alpha1" ) @@ -108,12 +109,12 @@ metadata: }, }) - serviceNetworkd := v1alpha1.NewService("networkd") - serviceNetworkd.SetRunning(true) - serviceNetworkd.SetHealthy(true) + statusNetwork := network.NewStatus(network.NamespaceName, network.StatusID) + statusNetwork.TypedSpec().AddressReady = true + statusNetwork.TypedSpec().ConnectivityReady = true suite.Require().NoError(suite.state.Create(suite.ctx, configExtraManifests)) - suite.Require().NoError(suite.state.Create(suite.ctx, serviceNetworkd)) + suite.Require().NoError(suite.state.Create(suite.ctx, statusNetwork)) suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( func() error { diff --git a/internal/app/machined/pkg/controllers/network/address_config.go b/internal/app/machined/pkg/controllers/network/address_config.go index cf99ae43c..1c120cc8a 100644 --- a/internal/app/machined/pkg/controllers/network/address_config.go +++ b/internal/app/machined/pkg/controllers/network/address_config.go @@ -16,6 +16,7 @@ import ( "go.uber.org/zap" "inet.af/netaddr" + "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" talosconfig "github.com/talos-systems/talos/pkg/machinery/config" "github.com/talos-systems/talos/pkg/machinery/nethelpers" "github.com/talos-systems/talos/pkg/resources/config" @@ -24,7 +25,8 @@ import ( // AddressConfigController manages network.AddressSpec based on machine configuration, kernel cmdline and some built-in defaults. type AddressConfigController struct { - Cmdline *procfs.Cmdline + Cmdline *procfs.Cmdline + V1Alpha1Mode runtime.Mode } // Name implements controller.Controller interface. @@ -179,6 +181,11 @@ func (ctrl *AddressConfigController) apply(ctx context.Context, r controller.Run } func (ctrl *AddressConfigController) loopbackDefaults() []network.AddressSpecSpec { + if ctrl.V1Alpha1Mode == runtime.ModeContainer { + // skip configuring lo addresses in container mode + return nil + } + return []network.AddressSpecSpec{ { Address: netaddr.IPPrefix{ diff --git a/internal/app/machined/pkg/controllers/network/address_config_test.go b/internal/app/machined/pkg/controllers/network/address_config_test.go index aec00902a..0e71e7a9e 100644 --- a/internal/app/machined/pkg/controllers/network/address_config_test.go +++ b/internal/app/machined/pkg/controllers/network/address_config_test.go @@ -235,6 +235,25 @@ func (suite *AddressConfigSuite) TestMachineConfiguration() { })) } +func (suite *AddressConfigSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + })) + if state.IsConflictError(err) { + err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) + } + + suite.Require().NoError(err) +} + func TestAddressConfigSuite(t *testing.T) { suite.Run(t, new(AddressConfigSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/address_merge.go b/internal/app/machined/pkg/controllers/network/address_merge.go index 22f17c187..237761425 100644 --- a/internal/app/machined/pkg/controllers/network/address_merge.go +++ b/internal/app/machined/pkg/controllers/network/address_merge.go @@ -3,6 +3,8 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. // Package network provides controllers which manage network resources. +// +//nolint:dupl package network import ( diff --git a/internal/app/machined/pkg/controllers/network/address_merge_test.go b/internal/app/machined/pkg/controllers/network/address_merge_test.go index 2059b44a2..8c227f66c 100644 --- a/internal/app/machined/pkg/controllers/network/address_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/address_merge_test.go @@ -190,6 +190,17 @@ func (suite *AddressMergeSuite) TestMerge() { })) } +func (suite *AddressMergeSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewAddressSpec(network.ConfigNamespaceName, "bar"))) +} + func TestAddressMergeSuite(t *testing.T) { suite.Run(t, new(AddressMergeSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/address_spec.go b/internal/app/machined/pkg/controllers/network/address_spec.go index a34cb34f5..dff28a86a 100644 --- a/internal/app/machined/pkg/controllers/network/address_spec.go +++ b/internal/app/machined/pkg/controllers/network/address_spec.go @@ -6,8 +6,10 @@ package network import ( "context" + "errors" "fmt" "net" + "os" "github.com/cosi-project/runtime/pkg/controller" "github.com/cosi-project/runtime/pkg/resource" @@ -48,7 +50,7 @@ func (ctrl *AddressSpecController) Outputs() []controller.Output { // Run implements controller.Controller interface. // -//nolint:gocyclo,dupl +//nolint:gocyclo func (ctrl *AddressSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { // watch link changes as some address might need to be re-applied if the link appears watcher, err := watch.NewRtNetlink(r, unix.RTMGRP_LINK) @@ -219,7 +221,10 @@ func (ctrl *AddressSpecController) syncAddress(ctx context.Context, r controller Flags: uint32(address.TypedSpec().Flags), }, }); err != nil { - return fmt.Errorf("error adding address %s to %q: %w", address.TypedSpec().Address, address.TypedSpec().LinkName, err) + // ignore EEXIST error + if !errors.Is(err, os.ErrExist) { + return fmt.Errorf("error adding address %s to %q: %w", address.TypedSpec().Address, address.TypedSpec().LinkName, err) + } } logger.Info("assigned address", zap.Stringer("address", address.TypedSpec().Address), zap.String("link", address.TypedSpec().LinkName)) diff --git a/internal/app/machined/pkg/controllers/network/address_spec_test.go b/internal/app/machined/pkg/controllers/network/address_spec_test.go index 78c442185..871054d5a 100644 --- a/internal/app/machined/pkg/controllers/network/address_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/address_spec_test.go @@ -9,6 +9,7 @@ import ( "context" "fmt" "log" + "math/rand" "net" "sync" "testing" @@ -58,6 +59,10 @@ func (suite *AddressSpecSuite) SetupTest() { suite.startRuntime() } +func (suite *AddressSpecSuite) uniqueDummyInterface() string { + return fmt.Sprintf("dummy%02x%02x%02x", rand.Int31()&0xff, rand.Int31()&0xff, rand.Int31()&0xff) +} + func (suite *AddressSpecSuite) startRuntime() { suite.wg.Add(1) @@ -163,7 +168,7 @@ func (suite *AddressSpecSuite) TestLoopback() { } func (suite *AddressSpecSuite) TestDummy() { - const dummyInterface = "dummy9" + dummyInterface := suite.uniqueDummyInterface() conn, err := rtnetlink.Dial(nil) suite.Require().NoError(err) @@ -223,6 +228,17 @@ func (suite *AddressSpecSuite) TestDummy() { } } +func (suite *AddressSpecSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewAddressSpec(network.NamespaceName, "bar"))) +} + func TestAddressSpecSuite(t *testing.T) { suite.Run(t, new(AddressSpecSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/address_status_test.go b/internal/app/machined/pkg/controllers/network/address_status_test.go index ab85aafdd..e83c745c2 100644 --- a/internal/app/machined/pkg/controllers/network/address_status_test.go +++ b/internal/app/machined/pkg/controllers/network/address_status_test.go @@ -104,6 +104,14 @@ func (suite *AddressStatusSuite) TestLoopback() { })) } +func (suite *AddressStatusSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() +} + func TestAddressStatusSuite(t *testing.T) { suite.Run(t, new(AddressStatusSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/etcfile_test.go b/internal/app/machined/pkg/controllers/network/etcfile_test.go index 2d68e0df3..b614e2be6 100644 --- a/internal/app/machined/pkg/controllers/network/etcfile_test.go +++ b/internal/app/machined/pkg/controllers/network/etcfile_test.go @@ -240,6 +240,29 @@ func (suite *EtcFileConfigSuite) TestOnlyHostname() { ) } +func (suite *EtcFileConfigSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + })) + if state.IsConflictError(err) { + err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) + } + + suite.Require().NoError(err) + + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewHostnameStatus(network.NamespaceName, "bar"))) + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewResolverStatus(network.NamespaceName, "bar"))) + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewNodeAddress(network.NamespaceName, "bar"))) +} + func TestEtcFileConfigSuite(t *testing.T) { suite.Run(t, new(EtcFileConfigSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/hostname_config_test.go b/internal/app/machined/pkg/controllers/network/hostname_config_test.go index 306d5f081..5e735e152 100644 --- a/internal/app/machined/pkg/controllers/network/hostname_config_test.go +++ b/internal/app/machined/pkg/controllers/network/hostname_config_test.go @@ -209,6 +209,27 @@ func (suite *HostnameConfigSuite) TestMachineConfiguration() { })) } +func (suite *HostnameConfigSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + })) + if state.IsConflictError(err) { + err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) + } + + suite.Require().NoError(err) + + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewNodeAddress(network.NamespaceName, "bar"))) +} + func TestHostnameConfigSuite(t *testing.T) { suite.Run(t, new(HostnameConfigSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/hostname_merge_test.go b/internal/app/machined/pkg/controllers/network/hostname_merge_test.go index 2edf8b00b..1e8a8eead 100644 --- a/internal/app/machined/pkg/controllers/network/hostname_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/hostname_merge_test.go @@ -132,6 +132,8 @@ func (suite *HostnameMergeSuite) TestMerge() { "hostname", }, func(r *network.HostnameSpec) error { suite.Assert().Equal("bar.com", r.TypedSpec().FQDN()) + suite.Assert().Equal("bar", r.TypedSpec().Hostname) + suite.Assert().Equal("com", r.TypedSpec().Domainname) return nil }) @@ -153,6 +155,17 @@ func (suite *HostnameMergeSuite) TestMerge() { })) } +func (suite *HostnameMergeSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewHostnameSpec(network.ConfigNamespaceName, "bar"))) +} + func TestHostnameMergeSuite(t *testing.T) { suite.Run(t, new(HostnameMergeSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/hostname_spec.go b/internal/app/machined/pkg/controllers/network/hostname_spec.go index 6d206f73e..5eec640e8 100644 --- a/internal/app/machined/pkg/controllers/network/hostname_spec.go +++ b/internal/app/machined/pkg/controllers/network/hostname_spec.go @@ -104,6 +104,8 @@ func (ctrl *HostnameSpecController) Run(ctx context.Context, r controller.Runtim // apply hostname unless running in container mode if ctrl.V1Alpha1Mode != v1alpha1runtime.ModeContainer { + logger.Info("setting hostname", zap.String("hostname", spec.TypedSpec().Hostname), zap.String("domainname", spec.TypedSpec().Domainname)) + if err = unix.Sethostname([]byte(spec.TypedSpec().Hostname)); err != nil { return fmt.Errorf("error setting hostname: %w", err) } diff --git a/internal/app/machined/pkg/controllers/network/hostname_spec_test.go b/internal/app/machined/pkg/controllers/network/hostname_spec_test.go index 0c1786025..076fbf891 100644 --- a/internal/app/machined/pkg/controllers/network/hostname_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/hostname_spec_test.go @@ -101,6 +101,17 @@ func (suite *HostnameSpecSuite) TestSpec() { })) } +func (suite *HostnameSpecSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewHostnameSpec(network.NamespaceName, "bar"))) +} + func TestHostnameSpecSuite(t *testing.T) { suite.Run(t, new(HostnameSpecSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/link_config_test.go b/internal/app/machined/pkg/controllers/network/link_config_test.go index a53f5adbf..b635442ab 100644 --- a/internal/app/machined/pkg/controllers/network/link_config_test.go +++ b/internal/app/machined/pkg/controllers/network/link_config_test.go @@ -382,6 +382,27 @@ func (suite *LinkConfigSuite) TestDefaultUp() { })) } +func (suite *LinkConfigSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + })) + if state.IsConflictError(err) { + err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) + } + + suite.Require().NoError(err) + + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkStatus(network.NamespaceName, "bar"))) +} + func TestLinkConfigSuite(t *testing.T) { suite.Run(t, new(LinkConfigSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/link_merge_test.go b/internal/app/machined/pkg/controllers/network/link_merge_test.go index d73c2b6e8..e60c7b06f 100644 --- a/internal/app/machined/pkg/controllers/network/link_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/link_merge_test.go @@ -185,6 +185,17 @@ func (suite *LinkMergeSuite) TestMerge() { })) } +func (suite *LinkMergeSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkSpec(network.ConfigNamespaceName, "bar"))) +} + func TestLinkMergeSuite(t *testing.T) { suite.Run(t, new(LinkMergeSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/link_spec_test.go b/internal/app/machined/pkg/controllers/network/link_spec_test.go index 4e9bb6b7d..edd194009 100644 --- a/internal/app/machined/pkg/controllers/network/link_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/link_spec_test.go @@ -554,6 +554,17 @@ func (suite *LinkSpecSuite) TestWireguard() { })) } +func (suite *LinkSpecSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkSpec(network.NamespaceName, "bar"))) +} + func TestLinkSpecSuite(t *testing.T) { suite.Run(t, new(LinkSpecSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/link_status_test.go b/internal/app/machined/pkg/controllers/network/link_status_test.go index 98a90a03c..2e1fa1863 100644 --- a/internal/app/machined/pkg/controllers/network/link_status_test.go +++ b/internal/app/machined/pkg/controllers/network/link_status_test.go @@ -9,6 +9,7 @@ import ( "context" "fmt" "log" + "math/rand" "net" "sync" "testing" @@ -67,6 +68,10 @@ func (suite *LinkStatusSuite) startRuntime() { }() } +func (suite *LinkStatusSuite) uniqueDummyInterface() string { + return fmt.Sprintf("dummy%02x%02x%02x", rand.Int31()&0xff, rand.Int31()&0xff, rand.Int31()&0xff) +} + func (suite *LinkStatusSuite) assertInterfaces(requiredIDs []string, check func(*network.LinkStatus) error) error { missingIDs := make(map[string]struct{}, len(requiredIDs)) @@ -127,7 +132,7 @@ func (suite *LinkStatusSuite) TestLoopbackInterface() { } func (suite *LinkStatusSuite) TestDummyInterface() { - const dummyInterface = "dummy9" + dummyInterface := suite.uniqueDummyInterface() conn, err := rtnetlink.Dial(nil) suite.Require().NoError(err) @@ -187,6 +192,17 @@ func (suite *LinkStatusSuite) TestDummyInterface() { })) } +func (suite *LinkStatusSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkRefresh(network.NamespaceName, "bar"))) +} + func TestLinkStatusSuite(t *testing.T) { suite.Run(t, new(LinkStatusSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/node_address_test.go b/internal/app/machined/pkg/controllers/network/node_address_test.go index 46237be8c..14b5aff76 100644 --- a/internal/app/machined/pkg/controllers/network/node_address_test.go +++ b/internal/app/machined/pkg/controllers/network/node_address_test.go @@ -125,6 +125,18 @@ func (suite *NodeAddressSuite) TestDefaults() { })) } +func (suite *NodeAddressSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewAddressStatus(network.NamespaceName, "bar"))) + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkStatus(network.NamespaceName, "bar"))) +} + func TestNodeAddressSuite(t *testing.T) { suite.Run(t, new(NodeAddressSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/operator/dhcp4.go b/internal/app/machined/pkg/controllers/network/operator/dhcp4.go index 6637a8114..a4e8a9cfc 100644 --- a/internal/app/machined/pkg/controllers/network/operator/dhcp4.go +++ b/internal/app/machined/pkg/controllers/network/operator/dhcp4.go @@ -148,6 +148,7 @@ func (d *DHCP4) TimeServerSpecs() []network.TimeServerSpecSpec { return d.timeservers } +//nolint:gocyclo func (d *DHCP4) parseAck(ack *dhcpv4.DHCPv4) { d.mu.Lock() defer d.mu.Unlock() @@ -194,6 +195,7 @@ func (d *DHCP4) parseAck(ack *dhcpv4.DHCPv4) { d.routes = append(d.routes, network.RouteSpecSpec{ Family: nethelpers.FamilyInet4, Destination: dst, + Source: addr, Gateway: gw, OutLinkName: d.linkName, Table: nethelpers.TableMain, @@ -222,6 +224,10 @@ func (d *DHCP4) parseAck(ack *dhcpv4.DHCPv4) { } } + for i := range d.routes { + d.routes[i].Normalize() + } + if len(ack.DNS()) > 0 { dns := make([]netaddr.IP, len(ack.DNS())) @@ -240,12 +246,20 @@ func (d *DHCP4) parseAck(ack *dhcpv4.DHCPv4) { } if ack.HostName() != "" { - d.hostname = []network.HostnameSpecSpec{ - { - Hostname: ack.HostName(), - Domainname: ack.DomainName(), - ConfigLayer: network.ConfigOperator, - }, + spec := network.HostnameSpecSpec{ + ConfigLayer: network.ConfigOperator, + } + + if err = spec.ParseFQDN(ack.HostName()); err == nil { + if ack.DomainName() != "" { + spec.Domainname = ack.DomainName() + } + + d.hostname = []network.HostnameSpecSpec{ + spec, + } + } else { + d.hostname = nil } } else { d.hostname = nil diff --git a/internal/app/machined/pkg/controllers/network/operator_config_test.go b/internal/app/machined/pkg/controllers/network/operator_config_test.go index 46b0ca743..76e66e705 100644 --- a/internal/app/machined/pkg/controllers/network/operator_config_test.go +++ b/internal/app/machined/pkg/controllers/network/operator_config_test.go @@ -456,6 +456,27 @@ func (suite *OperatorConfigSuite) TestMachineConfigurationVIP() { })) } +func (suite *OperatorConfigSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + })) + if state.IsConflictError(err) { + err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) + } + + suite.Require().NoError(err) + + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkStatus(network.NamespaceName, "bar"))) +} + func TestOperatorConfigSuite(t *testing.T) { suite.Run(t, new(OperatorConfigSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/platform_config_test.go b/internal/app/machined/pkg/controllers/network/platform_config_test.go new file mode 100644 index 000000000..347c84f6a --- /dev/null +++ b/internal/app/machined/pkg/controllers/network/platform_config_test.go @@ -0,0 +1,203 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//nolint:dupl +package network_test + +import ( + "context" + "fmt" + "log" + "net" + "sync" + "testing" + "time" + + "github.com/cosi-project/runtime/pkg/controller/runtime" + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/state" + "github.com/cosi-project/runtime/pkg/state/impl/inmem" + "github.com/cosi-project/runtime/pkg/state/impl/namespaced" + "github.com/stretchr/testify/suite" + "github.com/talos-systems/go-procfs/procfs" + "github.com/talos-systems/go-retry/retry" + + netctrl "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/network" + v1alpha1runtime "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" + "github.com/talos-systems/talos/pkg/logging" + "github.com/talos-systems/talos/pkg/resources/network" +) + +type PlatformConfigSuite struct { + suite.Suite + + state state.State + + runtime *runtime.Runtime + wg sync.WaitGroup + + ctx context.Context + ctxCancel context.CancelFunc +} + +func (suite *PlatformConfigSuite) SetupTest() { + suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute) + + suite.state = state.WrapCore(namespaced.NewState(inmem.Build)) + + var err error + + suite.runtime, err = runtime.NewRuntime(suite.state, logging.Wrap(log.Writer())) + suite.Require().NoError(err) +} + +func (suite *PlatformConfigSuite) startRuntime() { + suite.wg.Add(1) + + go func() { + defer suite.wg.Done() + + suite.Assert().NoError(suite.runtime.Run(suite.ctx)) + }() +} + +func (suite *PlatformConfigSuite) assertHostnames(requiredIDs []string, check func(*network.HostnameSpec) error) error { + missingIDs := make(map[string]struct{}, len(requiredIDs)) + + for _, id := range requiredIDs { + missingIDs[id] = struct{}{} + } + + resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.HostnameSpecType, "", resource.VersionUndefined)) + if err != nil { + return err + } + + for _, res := range resources.Items { + _, required := missingIDs[res.Metadata().ID()] + if !required { + continue + } + + delete(missingIDs, res.Metadata().ID()) + + if err = check(res.(*network.HostnameSpec)); err != nil { + return retry.ExpectedError(err) + } + } + + if len(missingIDs) > 0 { + return retry.ExpectedError(fmt.Errorf("some resources are missing: %q", missingIDs)) + } + + return nil +} + +func (suite *PlatformConfigSuite) assertNoHostname(id string) error { + resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.HostnameSpecType, "", resource.VersionUndefined)) + if err != nil { + return err + } + + for _, res := range resources.Items { + if res.Metadata().ID() == id { + return retry.ExpectedError(fmt.Errorf("spec %q is still there", id)) + } + } + + return nil +} + +func (suite *PlatformConfigSuite) TestNoPlatform() { + suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{})) + + suite.startRuntime() + + suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( + func() error { + return suite.assertNoHostname("platform/hostname") + })) +} + +func (suite *PlatformConfigSuite) TestPlatformMock() { + suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ + V1alpha1Platform: &platformMock{hostname: []byte("talos-e2e-897b4e49-gcp-controlplane-jvcnl.c.talos-testbed.internal")}, + })) + + suite.startRuntime() + + suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( + func() error { + return suite.assertHostnames([]string{ + "platform/hostname", + }, func(r *network.HostnameSpec) error { + suite.Assert().Equal("talos-e2e-897b4e49-gcp-controlplane-jvcnl", r.TypedSpec().Hostname) + suite.Assert().Equal("c.talos-testbed.internal", r.TypedSpec().Domainname) + suite.Assert().Equal(network.ConfigPlatform, r.TypedSpec().ConfigLayer) + + return nil + }) + })) +} + +func (suite *PlatformConfigSuite) TestPlatformMockNoDomain() { + suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ + V1alpha1Platform: &platformMock{hostname: []byte("talos-e2e-897b4e49-gcp-controlplane-jvcnl")}, + })) + + suite.startRuntime() + + suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( + func() error { + return suite.assertHostnames([]string{ + "platform/hostname", + }, func(r *network.HostnameSpec) error { + suite.Assert().Equal("talos-e2e-897b4e49-gcp-controlplane-jvcnl", r.TypedSpec().Hostname) + suite.Assert().Equal("", r.TypedSpec().Domainname) + suite.Assert().Equal(network.ConfigPlatform, r.TypedSpec().ConfigLayer) + + return nil + }) + })) +} + +func (suite *PlatformConfigSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() +} + +func TestPlatformConfigSuite(t *testing.T) { + suite.Run(t, new(PlatformConfigSuite)) +} + +type platformMock struct { + hostname []byte +} + +func (mock *platformMock) Name() string { + return "mock" +} + +func (mock *platformMock) Configuration(context.Context) ([]byte, error) { + return nil, nil +} + +func (mock *platformMock) Hostname(context.Context) ([]byte, error) { + return mock.hostname, nil +} + +func (mock *platformMock) Mode() v1alpha1runtime.Mode { + return v1alpha1runtime.ModeCloud +} + +func (mock *platformMock) ExternalIPs(context.Context) ([]net.IP, error) { + return nil, nil +} + +func (mock *platformMock) KernelArgs() procfs.Parameters { + return nil +} diff --git a/internal/app/machined/pkg/controllers/network/resolver_config_test.go b/internal/app/machined/pkg/controllers/network/resolver_config_test.go index 77a0f9193..dd0f143d0 100644 --- a/internal/app/machined/pkg/controllers/network/resolver_config_test.go +++ b/internal/app/machined/pkg/controllers/network/resolver_config_test.go @@ -199,6 +199,25 @@ func (suite *ResolverConfigSuite) TestMachineConfiguration() { })) } +func (suite *ResolverConfigSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + })) + if state.IsConflictError(err) { + err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) + } + + suite.Require().NoError(err) +} + func TestResolverConfigSuite(t *testing.T) { suite.Run(t, new(ResolverConfigSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/resolver_merge_test.go b/internal/app/machined/pkg/controllers/network/resolver_merge_test.go index 11fcd1893..125c11035 100644 --- a/internal/app/machined/pkg/controllers/network/resolver_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/resolver_merge_test.go @@ -154,6 +154,17 @@ func (suite *ResolverMergeSuite) TestMerge() { })) } +func (suite *ResolverMergeSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewResolverSpec(network.ConfigNamespaceName, "bar"))) +} + func TestResolverMergeSuite(t *testing.T) { suite.Run(t, new(ResolverMergeSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/resolver_spec_test.go b/internal/app/machined/pkg/controllers/network/resolver_spec_test.go index 899d2a3e3..d5c333077 100644 --- a/internal/app/machined/pkg/controllers/network/resolver_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/resolver_spec_test.go @@ -101,6 +101,17 @@ func (suite *ResolverSpecSuite) TestSpec() { })) } +func (suite *ResolverSpecSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewResolverSpec(network.NamespaceName, "bar"))) +} + func TestResolverSpecSuite(t *testing.T) { suite.Run(t, new(ResolverSpecSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/route_config.go b/internal/app/machined/pkg/controllers/network/route_config.go index 4da8aa79f..1589d920f 100644 --- a/internal/app/machined/pkg/controllers/network/route_config.go +++ b/internal/app/machined/pkg/controllers/network/route_config.go @@ -200,15 +200,12 @@ func (ctrl *RouteConfigController) parseCmdline(logger *zap.Logger) (route netwo route.OutLinkName = settings.LinkName route.ConfigLayer = network.ConfigCmdline + route.Normalize() + return route } -var ( - zero16 = netaddr.MustParseIP("::") - zero4 = netaddr.MustParseIP("0.0.0.0") -) - -//nolint:gocyclo,cyclop +//nolint:gocyclo func (ctrl *RouteConfigController) parseMachineConfiguration(logger *zap.Logger, cfgProvider talosconfig.Provider) (routes []network.RouteSpecSpec) { convert := func(linkName string, in talosconfig.Route) (route network.RouteSpecSpec, err error) { if in.Network() != "" { @@ -216,11 +213,6 @@ func (ctrl *RouteConfigController) parseMachineConfiguration(logger *zap.Logger, if err != nil { return route, fmt.Errorf("error parsing route network: %w", err) } - - if route.Destination.Bits == 0 && (route.Destination.IP.Compare(zero4) == 0 || route.Destination.IP.Compare(zero16) == 0) { - // clear destination to be zero value to support "0.0.0.0/0" routes - route.Destination = netaddr.IPPrefix{} - } } route.Gateway, err = netaddr.ParseIP(in.Gateway()) @@ -228,6 +220,8 @@ func (ctrl *RouteConfigController) parseMachineConfiguration(logger *zap.Logger, return route, fmt.Errorf("error parsing route gateway: %w", err) } + route.Normalize() + route.Priority = in.Metric() if route.Priority == 0 { route.Priority = DefaultRouteMetric @@ -244,15 +238,6 @@ func (ctrl *RouteConfigController) parseMachineConfiguration(logger *zap.Logger, route.OutLinkName = linkName route.ConfigLayer = network.ConfigMachineConfiguration - switch { - case route.Destination.IP.IsLinkLocalUnicast() || route.Destination.IP.IsLinkLocalMulticast(): - route.Scope = nethelpers.ScopeLink - case route.Destination.IP.IsLoopback(): - route.Scope = nethelpers.ScopeHost - default: - route.Scope = nethelpers.ScopeGlobal - } - route.Type = nethelpers.TypeUnicast if route.Destination.IP.IsMulticast() { diff --git a/internal/app/machined/pkg/controllers/network/route_config_test.go b/internal/app/machined/pkg/controllers/network/route_config_test.go index 825271469..86b77f053 100644 --- a/internal/app/machined/pkg/controllers/network/route_config_test.go +++ b/internal/app/machined/pkg/controllers/network/route_config_test.go @@ -106,7 +106,7 @@ func (suite *RouteConfigSuite) TestCmdline() { suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( func() error { return suite.assertRoutes([]string{ - "cmdline//172.20.0.1", + "cmdline/172.20.0.1/", }, func(r *network.RouteSpec) error { suite.Assert().Equal("eth1", r.TypedSpec().OutLinkName) suite.Assert().Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer) @@ -195,20 +195,20 @@ func (suite *RouteConfigSuite) TestMachineConfiguration() { suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( func() error { return suite.assertRoutes([]string{ - "configuration//2001:470:6d:30e:8ed2:b60c:9d2f:803b", - "configuration/10.0.3.0/24/10.0.3.1", - "configuration/192.168.0.0/18/192.168.0.25", + "configuration/2001:470:6d:30e:8ed2:b60c:9d2f:803b/", + "configuration/10.0.3.1/10.0.3.0/24", + "configuration/192.168.0.25/192.168.0.0/18", }, func(r *network.RouteSpec) error { switch r.Metadata().ID() { - case "configuration//2001:470:6d:30e:8ed2:b60c:9d2f:803b": + case "configuration/2001:470:6d:30e:8ed2:b60c:9d2f:803b/": suite.Assert().Equal("eth2", r.TypedSpec().OutLinkName) suite.Assert().Equal(nethelpers.FamilyInet6, r.TypedSpec().Family) suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority) - case "configuration/10.0.3.0/24/10.0.3.1": + case "configuration/10.0.3.1/10.0.3.0/24": suite.Assert().Equal("eth0.24", r.TypedSpec().OutLinkName) suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family) suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority) - case "configuration/192.168.0.0/18/192.168.0.25": + case "configuration/192.168.0.25/192.168.0.0/18": suite.Assert().Equal("eth3", r.TypedSpec().OutLinkName) suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family) suite.Assert().EqualValues(25, r.TypedSpec().Priority) @@ -221,6 +221,25 @@ func (suite *RouteConfigSuite) TestMachineConfiguration() { })) } +func (suite *RouteConfigSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + })) + if state.IsConflictError(err) { + err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) + } + + suite.Require().NoError(err) +} + func TestRouteConfigSuite(t *testing.T) { suite.Run(t, new(RouteConfigSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/route_merge.go b/internal/app/machined/pkg/controllers/network/route_merge.go index 5688c1042..0a3424289 100644 --- a/internal/app/machined/pkg/controllers/network/route_merge.go +++ b/internal/app/machined/pkg/controllers/network/route_merge.go @@ -3,6 +3,8 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. // Package network provides controllers which manage network resources. +// +//nolint:dupl package network import ( diff --git a/internal/app/machined/pkg/controllers/network/route_merge_test.go b/internal/app/machined/pkg/controllers/network/route_merge_test.go index a80f19a2b..596f86460 100644 --- a/internal/app/machined/pkg/controllers/network/route_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/route_merge_test.go @@ -154,13 +154,13 @@ func (suite *RouteMergeSuite) TestMerge() { suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( func() error { return suite.assertRoutes([]string{ - "/10.5.0.3", - "10.0.0.35/32/10.0.0.34", + "10.5.0.3/", + "10.0.0.34/10.0.0.35/32", }, func(r *network.RouteSpec) error { switch r.Metadata().ID() { - case "/10.5.0.3": + case "10.5.0.3/": suite.Assert().Equal(*dhcp.TypedSpec(), *r.TypedSpec()) - case "10.0.0.35/32/10.0.0.34": + case "10.0.0.34/10.0.0.35/32": suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec()) } @@ -173,16 +173,16 @@ func (suite *RouteMergeSuite) TestMerge() { suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( func() error { return suite.assertRoutes([]string{ - "/10.5.0.3", - "10.0.0.35/32/10.0.0.34", + "10.5.0.3/", + "10.0.0.34/10.0.0.35/32", }, func(r *network.RouteSpec) error { switch r.Metadata().ID() { - case "/10.5.0.3": + case "10.5.0.3/": if *cmdline.TypedSpec() != *r.TypedSpec() { // using retry here, as it might not be reconciled immediately return retry.ExpectedError(fmt.Errorf("not equal yet")) } - case "10.0.0.35/32/10.0.0.34": + case "10.0.0.34/10.0.0.35/32": suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec()) } @@ -194,10 +194,21 @@ func (suite *RouteMergeSuite) TestMerge() { suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( func() error { - return suite.assertNoRoute("10.0.0.35/32/10.0.0.34") + return suite.assertNoRoute("10.0.0.34/10.0.0.35/32") })) } +func (suite *RouteMergeSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewRouteSpec(network.ConfigNamespaceName, "bar"))) +} + func TestRouteMergeSuite(t *testing.T) { suite.Run(t, new(RouteMergeSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/route_spec.go b/internal/app/machined/pkg/controllers/network/route_spec.go index aa6ec97b7..d7c02b858 100644 --- a/internal/app/machined/pkg/controllers/network/route_spec.go +++ b/internal/app/machined/pkg/controllers/network/route_spec.go @@ -10,12 +10,14 @@ import ( "github.com/cosi-project/runtime/pkg/controller" "github.com/cosi-project/runtime/pkg/resource" + "github.com/hashicorp/go-multierror" "github.com/jsimonetti/rtnetlink" "go.uber.org/zap" "golang.org/x/sys/unix" "inet.af/netaddr" "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/network/watch" + "github.com/talos-systems/talos/pkg/machinery/nethelpers" "github.com/talos-systems/talos/pkg/resources/network" ) @@ -45,10 +47,10 @@ func (ctrl *RouteSpecController) Outputs() []controller.Output { // Run implements controller.Controller interface. // -//nolint:gocyclo,dupl +//nolint:gocyclo func (ctrl *RouteSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { // watch link changes as some routes might need to be re-applied if the link appears - watcher, err := watch.NewRtNetlink(r, unix.RTMGRP_LINK) + watcher, err := watch.NewRtNetlink(r, unix.RTMGRP_LINK|unix.RTMGRP_IPV4_ROUTE) if err != nil { return err } @@ -98,18 +100,24 @@ func (ctrl *RouteSpecController) Run(ctx context.Context, r controller.Runtime, return fmt.Errorf("error listing addresses: %w", err) } - // loop over route and make reconcile decision + var multiErr *multierror.Error + + // loop over routes and make reconcile decision for _, res := range list.Items { route := res.(*network.RouteSpec) //nolint:forcetypeassert,errcheck if err = ctrl.syncRoute(ctx, r, logger, conn, links, routes, route); err != nil { - return err + multiErr = multierror.Append(multiErr, err) } } + + if err = multiErr.ErrorOrNil(); err != nil { + return err + } } } -func findRoutes(routes []rtnetlink.RouteMessage, destination netaddr.IPPrefix, gateway netaddr.IP) []*rtnetlink.RouteMessage { +func findRoutes(routes []rtnetlink.RouteMessage, destination netaddr.IPPrefix, gateway netaddr.IP, table nethelpers.RoutingTable) []*rtnetlink.RouteMessage { var result []*rtnetlink.RouteMessage //nolint:prealloc for i, route := range routes { @@ -125,13 +133,17 @@ func findRoutes(routes []rtnetlink.RouteMessage, destination netaddr.IPPrefix, g continue } + if nethelpers.RoutingTable(route.Table) != table { + continue + } + result = append(result, &routes[i]) } return result } -//nolint:gocyclo +//nolint:gocyclo,cyclop func (ctrl *RouteSpecController) syncRoute(ctx context.Context, r controller.Runtime, logger *zap.Logger, conn *rtnetlink.Conn, links []rtnetlink.LinkMessage, routes []rtnetlink.RouteMessage, route *network.RouteSpec) error { linkIndex := resolveLinkName(links, route.TypedSpec().OutLinkName) @@ -144,7 +156,7 @@ func (ctrl *RouteSpecController) syncRoute(ctx context.Context, r controller.Run switch route.Metadata().Phase() { case resource.PhaseTearingDown: - for _, existing := range findRoutes(routes, route.TypedSpec().Destination, route.TypedSpec().Gateway) { + for _, existing := range findRoutes(routes, route.TypedSpec().Destination, route.TypedSpec().Gateway, route.TypedSpec().Table) { // delete route if err := conn.Route.Delete(existing); err != nil { return fmt.Errorf("error removing route: %w", err) @@ -165,15 +177,17 @@ func (ctrl *RouteSpecController) syncRoute(ctx context.Context, r controller.Run matchFound := false - for _, existing := range findRoutes(routes, route.TypedSpec().Destination, route.TypedSpec().Gateway) { + for _, existing := range findRoutes(routes, route.TypedSpec().Destination, route.TypedSpec().Gateway, route.TypedSpec().Table) { // check if existing matches the spec: if it does, skip update if existing.Scope == uint8(route.TypedSpec().Scope) && existing.Flags == uint32(route.TypedSpec().Flags) && existing.Protocol == uint8(route.TypedSpec().Protocol) && existing.Flags == uint32(route.TypedSpec().Flags) && existing.Attributes.OutIface == linkIndex && existing.Attributes.Priority == route.TypedSpec().Priority && - existing.Attributes.Table == uint32(route.TypedSpec().Table) { + existing.Attributes.Table == uint32(route.TypedSpec().Table) && + (route.TypedSpec().Source.IsZero() || + existing.Attributes.Src.Equal(route.TypedSpec().Source.IP.IPAddr().IP)) { matchFound = true - break + continue } // delete route, it doesn't match the spec @@ -192,12 +206,14 @@ func (ctrl *RouteSpecController) syncRoute(ctx context.Context, r controller.Run msg := &rtnetlink.RouteMessage{ Family: uint8(route.TypedSpec().Family), DstLength: route.TypedSpec().Destination.Bits, + SrcLength: route.TypedSpec().Source.Bits, Protocol: uint8(route.TypedSpec().Protocol), Scope: uint8(route.TypedSpec().Scope), Type: uint8(route.TypedSpec().Type), Flags: uint32(route.TypedSpec().Flags), Attributes: rtnetlink.RouteAttributes{ Dst: route.TypedSpec().Destination.IP.IPAddr().IP, + Src: route.TypedSpec().Source.IP.IPAddr().IP, Gateway: route.TypedSpec().Gateway.IPAddr().IP, OutIface: linkIndex, Priority: route.TypedSpec().Priority, diff --git a/internal/app/machined/pkg/controllers/network/route_spec_test.go b/internal/app/machined/pkg/controllers/network/route_spec_test.go index 87498ad00..bbd90421c 100644 --- a/internal/app/machined/pkg/controllers/network/route_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/route_spec_test.go @@ -9,6 +9,8 @@ import ( "context" "fmt" "log" + "math/rand" + "net" "sync" "testing" "time" @@ -21,6 +23,7 @@ import ( "github.com/jsimonetti/rtnetlink" "github.com/stretchr/testify/suite" "github.com/talos-systems/go-retry/retry" + "golang.org/x/sys/unix" "inet.af/netaddr" netctrl "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/network" @@ -56,6 +59,10 @@ func (suite *RouteSpecSuite) SetupTest() { suite.startRuntime() } +func (suite *RouteSpecSuite) uniqueDummyInterface() string { + return fmt.Sprintf("dummy%02x%02x%02x", rand.Int31()&0xff, rand.Int31()&0xff, rand.Int31()&0xff) +} + func (suite *RouteSpecSuite) startRuntime() { suite.wg.Add(1) @@ -241,6 +248,139 @@ func (suite *RouteSpecSuite) TestDefaultRoute() { suite.Require().NoError(suite.state.Destroy(suite.ctx, def.Metadata())) } +func (suite *RouteSpecSuite) TestDefaultAndInterfaceRoutes() { + dummyInterface := suite.uniqueDummyInterface() + + conn, err := rtnetlink.Dial(nil) + suite.Require().NoError(err) + + defer conn.Close() //nolint:errcheck + + suite.Require().NoError(conn.Link.New(&rtnetlink.LinkMessage{ + Type: unix.ARPHRD_ETHER, + Flags: unix.IFF_UP, + Change: unix.IFF_UP, + Attributes: &rtnetlink.LinkAttributes{ + Name: dummyInterface, + MTU: 1400, + Info: &rtnetlink.LinkInfo{ + Kind: "dummy", + }, + }, + })) + + iface, err := net.InterfaceByName(dummyInterface) + suite.Require().NoError(err) + + defer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck + + localIP := net.ParseIP("10.28.0.27").To4() + + suite.Require().NoError(conn.Address.New(&rtnetlink.AddressMessage{ + Family: unix.AF_INET, + PrefixLength: 32, + Scope: unix.RT_SCOPE_UNIVERSE, + Index: uint32(iface.Index), + Attributes: rtnetlink.AddressAttributes{ + Address: localIP, + Local: localIP, + }, + })) + + def := network.NewRouteSpec(network.NamespaceName, "default") + *def.TypedSpec() = network.RouteSpecSpec{ + Family: nethelpers.FamilyInet4, + Destination: netaddr.IPPrefix{}, + Gateway: netaddr.MustParseIP("10.28.0.1"), + Source: netaddr.MustParseIPPrefix("10.28.0.27/32"), + Table: nethelpers.TableMain, + OutLinkName: dummyInterface, + Protocol: nethelpers.ProtocolStatic, + Type: nethelpers.TypeUnicast, + Priority: 1048576, + ConfigLayer: network.ConfigMachineConfiguration, + } + def.TypedSpec().Normalize() + + host := network.NewRouteSpec(network.NamespaceName, "aninterface") + *host.TypedSpec() = network.RouteSpecSpec{ + Family: nethelpers.FamilyInet4, + Destination: netaddr.MustParseIPPrefix("10.28.0.1/32"), + Gateway: netaddr.MustParseIP("0.0.0.0"), + Source: netaddr.MustParseIPPrefix("10.28.0.27/32"), + Table: nethelpers.TableMain, + OutLinkName: dummyInterface, + Protocol: nethelpers.ProtocolStatic, + Type: nethelpers.TypeUnicast, + Priority: 1048576, + ConfigLayer: network.ConfigMachineConfiguration, + } + host.TypedSpec().Normalize() + + for _, res := range []resource.Resource{def, host} { + suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) + } + + suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( + func() error { + if err := suite.assertRoute(netaddr.IPPrefix{}, netaddr.MustParseIP("10.28.0.1"), func(route rtnetlink.RouteMessage) error { + suite.Assert().Nil(route.Attributes.Dst) + suite.Assert().EqualValues(1048576, route.Attributes.Priority) + + return nil + }); err != nil { + return err + } + + return suite.assertRoute(netaddr.MustParseIPPrefix("10.28.0.1/32"), netaddr.IP{}, func(route rtnetlink.RouteMessage) error { + suite.Assert().Nil(route.Attributes.Gateway) + suite.Assert().EqualValues(1048576, route.Attributes.Priority) + + return nil + }) + })) + + // teardown the routes + for { + ready, err := suite.state.Teardown(suite.ctx, def.Metadata()) + suite.Require().NoError(err) + + if ready { + break + } + + time.Sleep(100 * time.Millisecond) + } + + for { + ready, err := suite.state.Teardown(suite.ctx, host.Metadata()) + suite.Require().NoError(err) + + if ready { + break + } + + time.Sleep(100 * time.Millisecond) + } + + // torn down route should be removed immediately + suite.Assert().NoError(suite.assertNoRoute(netaddr.IPPrefix{}, netaddr.MustParseIP("10.28.0.1"))) + suite.Assert().NoError(suite.assertNoRoute(netaddr.MustParseIPPrefix("10.28.0.1/32"), netaddr.IP{})) + + suite.Require().NoError(suite.state.Destroy(suite.ctx, def.Metadata())) +} + +func (suite *RouteSpecSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewRouteSpec(network.NamespaceName, "bar"))) +} + func TestRouteSpecSuite(t *testing.T) { suite.Run(t, new(RouteSpecSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/route_status_test.go b/internal/app/machined/pkg/controllers/network/route_status_test.go index 5349bdddd..98f1de950 100644 --- a/internal/app/machined/pkg/controllers/network/route_status_test.go +++ b/internal/app/machined/pkg/controllers/network/route_status_test.go @@ -99,7 +99,7 @@ func (suite *RouteStatusSuite) assertRoutes(requiredIDs []string, check func(*ne func (suite *RouteStatusSuite) TestRoutes() { suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( func() error { - return suite.assertRoutes([]string{"127.0.0.0/8/"}, func(r *network.RouteStatus) error { + return suite.assertRoutes([]string{"/127.0.0.0/8"}, func(r *network.RouteStatus) error { suite.Assert().True(r.TypedSpec().Source.IP.IsLoopback()) suite.Assert().Equal("lo", r.TypedSpec().OutLinkName) suite.Assert().Equal(nethelpers.TableLocal, r.TypedSpec().Table) @@ -112,6 +112,14 @@ func (suite *RouteStatusSuite) TestRoutes() { })) } +func (suite *RouteStatusSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() +} + func TestRouteStatusSuite(t *testing.T) { suite.Run(t, new(RouteStatusSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/status_test.go b/internal/app/machined/pkg/controllers/network/status_test.go index 516b798ec..ed09c9d84 100644 --- a/internal/app/machined/pkg/controllers/network/status_test.go +++ b/internal/app/machined/pkg/controllers/network/status_test.go @@ -137,6 +137,20 @@ func (suite *StatusSuite) TestEtcFiles() { })) } +func (suite *StatusSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewNodeAddress(network.NamespaceName, "bar"))) + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewResolverStatus(network.NamespaceName, "bar"))) + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewHostnameStatus(network.NamespaceName, "bar"))) + suite.Assert().NoError(suite.state.Create(context.Background(), files.NewEtcFileStatus(files.NamespaceName, "bar"))) +} + func TestStatusSuite(t *testing.T) { suite.Run(t, new(StatusSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/timeserver_config_test.go b/internal/app/machined/pkg/controllers/network/timeserver_config_test.go index 2e281f3c5..cc1c51e17 100644 --- a/internal/app/machined/pkg/controllers/network/timeserver_config_test.go +++ b/internal/app/machined/pkg/controllers/network/timeserver_config_test.go @@ -198,6 +198,25 @@ func (suite *TimeServerConfigSuite) TestMachineConfiguration() { })) } +func (suite *TimeServerConfigSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ + ConfigVersion: "v1alpha1", + MachineConfig: &v1alpha1.MachineConfig{}, + })) + if state.IsConflictError(err) { + err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) + } + + suite.Require().NoError(err) +} + func TestTimeServerConfigSuite(t *testing.T) { suite.Run(t, new(TimeServerConfigSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/timeserver_merge_test.go b/internal/app/machined/pkg/controllers/network/timeserver_merge_test.go index 706017dc8..043e129a1 100644 --- a/internal/app/machined/pkg/controllers/network/timeserver_merge_test.go +++ b/internal/app/machined/pkg/controllers/network/timeserver_merge_test.go @@ -153,6 +153,17 @@ func (suite *TimeServerMergeSuite) TestMerge() { })) } +func (suite *TimeServerMergeSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewTimeServerSpec(network.ConfigNamespaceName, "bar"))) +} + func TestTimeServerMergeSuite(t *testing.T) { suite.Run(t, new(TimeServerMergeSuite)) } diff --git a/internal/app/machined/pkg/controllers/network/timeserver_spec_test.go b/internal/app/machined/pkg/controllers/network/timeserver_spec_test.go index cad6c326e..ceb060cf8 100644 --- a/internal/app/machined/pkg/controllers/network/timeserver_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/timeserver_spec_test.go @@ -100,6 +100,17 @@ func (suite *TimeServerSpecSuite) TestSpec() { })) } +func (suite *TimeServerSpecSuite) TearDownTest() { + suite.T().Log("tear down") + + suite.ctxCancel() + + suite.wg.Wait() + + // trigger updates in resources to stop watch loops + suite.Assert().NoError(suite.state.Create(context.Background(), network.NewTimeServerSpec(network.NamespaceName, "bar"))) +} + func TestTimeServerSpecSuite(t *testing.T) { suite.Run(t, new(TimeServerSpecSuite)) } diff --git a/internal/app/machined/pkg/controllers/secrets/etcd.go b/internal/app/machined/pkg/controllers/secrets/etcd.go index c3f04f7ae..260ce1b36 100644 --- a/internal/app/machined/pkg/controllers/secrets/etcd.go +++ b/internal/app/machined/pkg/controllers/secrets/etcd.go @@ -15,6 +15,7 @@ import ( "go.uber.org/zap" "github.com/talos-systems/talos/internal/pkg/etcd" + "github.com/talos-systems/talos/pkg/resources/network" "github.com/talos-systems/talos/pkg/resources/secrets" "github.com/talos-systems/talos/pkg/resources/time" "github.com/talos-systems/talos/pkg/resources/v1alpha1" @@ -38,9 +39,9 @@ func (ctrl *EtcdController) Inputs() []controller.Input { Kind: controller.InputWeak, }, { - Namespace: v1alpha1.NamespaceName, - Type: v1alpha1.ServiceType, - ID: pointer.ToString("networkd"), + Namespace: network.NamespaceName, + Type: network.StatusType, + ID: pointer.ToString(network.StatusID), Kind: controller.InputWeak, }, { @@ -88,8 +89,8 @@ func (ctrl *EtcdController) Run(ctx context.Context, r controller.Runtime, logge etcdRoot := etcdRootRes.(*secrets.Root).EtcdSpec() - // wait for networkd to be healthy as it might change IPs/hostname - networkdResource, err := r.Get(ctx, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, "networkd", resource.VersionUndefined)) + // wait for network to be ready as it might change IPs/hostname + networkResource, err := r.Get(ctx, resource.NewMetadata(network.NamespaceName, network.StatusType, network.StatusID, resource.VersionUndefined)) if err != nil { if state.IsNotFoundError(err) { continue @@ -98,7 +99,9 @@ func (ctrl *EtcdController) Run(ctx context.Context, r controller.Runtime, logge return err } - if !networkdResource.(*v1alpha1.Service).Healthy() { + networkStatus := networkResource.(*network.Status).TypedSpec() + + if !(networkStatus.AddressReady && networkStatus.HostnameReady) { continue } diff --git a/internal/app/machined/pkg/controllers/secrets/kubernetes.go b/internal/app/machined/pkg/controllers/secrets/kubernetes.go index 43e2533ab..30b66109f 100644 --- a/internal/app/machined/pkg/controllers/secrets/kubernetes.go +++ b/internal/app/machined/pkg/controllers/secrets/kubernetes.go @@ -22,6 +22,7 @@ import ( "github.com/talos-systems/talos/internal/pkg/kubeconfig" "github.com/talos-systems/talos/pkg/machinery/config" "github.com/talos-systems/talos/pkg/machinery/constants" + "github.com/talos-systems/talos/pkg/resources/network" "github.com/talos-systems/talos/pkg/resources/secrets" timeresource "github.com/talos-systems/talos/pkg/resources/time" "github.com/talos-systems/talos/pkg/resources/v1alpha1" @@ -44,21 +45,9 @@ func (ctrl *KubernetesController) Name() string { func (ctrl *KubernetesController) Inputs() []controller.Input { return []controller.Input{ { - Namespace: secrets.NamespaceName, - Type: secrets.RootType, - ID: pointer.ToString(secrets.RootKubernetesID), - Kind: controller.InputWeak, - }, - { - Namespace: v1alpha1.NamespaceName, - Type: v1alpha1.ServiceType, - ID: pointer.ToString("networkd"), - Kind: controller.InputWeak, - }, - { - Namespace: v1alpha1.NamespaceName, - Type: timeresource.StatusType, - ID: pointer.ToString(timeresource.StatusID), + Namespace: network.NamespaceName, + Type: network.StatusType, + ID: pointer.ToString(network.StatusID), Kind: controller.InputWeak, }, } @@ -78,6 +67,50 @@ func (ctrl *KubernetesController) Outputs() []controller.Output { // //nolint:gocyclo func (ctrl *KubernetesController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { + // wait for the network to be ready first, then switch to regular inputs + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + // wait for network to be ready as it might change IPs/hostname + networkResource, err := r.Get(ctx, resource.NewMetadata(network.NamespaceName, network.StatusType, network.StatusID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return err + } + + networkStatus := networkResource.(*network.Status).TypedSpec() + + if networkStatus.AddressReady && networkStatus.HostnameReady { + break + } + } + + // switch to regular inputs once the network is ready + if err := r.UpdateInputs([]controller.Input{ + { + Namespace: secrets.NamespaceName, + Type: secrets.RootType, + ID: pointer.ToString(secrets.RootKubernetesID), + Kind: controller.InputWeak, + }, + { + Namespace: v1alpha1.NamespaceName, + Type: timeresource.StatusType, + ID: pointer.ToString(timeresource.StatusID), + Kind: controller.InputWeak, + }, + }); err != nil { + return fmt.Errorf("error updating inputs: %w", err) + } + + r.QueueReconcile() + refreshTicker := time.NewTicker(KubernetesCertificateValidityDuration / 2) defer refreshTicker.Stop() @@ -104,20 +137,6 @@ func (ctrl *KubernetesController) Run(ctx context.Context, r controller.Runtime, k8sRoot := k8sRootRes.(*secrets.Root).KubernetesSpec() - // wait for networkd to be healthy as it might change IPs/hostname - networkdResource, err := r.Get(ctx, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, "networkd", resource.VersionUndefined)) - if err != nil { - if state.IsNotFoundError(err) { - continue - } - - return err - } - - if !networkdResource.(*v1alpha1.Service).Healthy() { - continue - } - // wait for time sync as certs depend on current time timeSyncResource, err := r.Get(ctx, resource.NewMetadata(v1alpha1.NamespaceName, timeresource.StatusType, timeresource.StatusID, resource.VersionUndefined)) if err != nil { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/packet/packet.go b/internal/app/machined/pkg/runtime/v1alpha1/platform/packet/packet.go index afc35646d..10fb65947 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/packet/packet.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/packet/packet.go @@ -15,10 +15,10 @@ import ( "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" "github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors" - "github.com/talos-systems/talos/internal/app/networkd/pkg/nic" "github.com/talos-systems/talos/pkg/download" "github.com/talos-systems/talos/pkg/machinery/config/configloader" "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1" + "github.com/talos-systems/talos/pkg/machinery/nethelpers" ) // Metadata holds packet metadata info. @@ -113,7 +113,7 @@ func (p *Packet) Configuration(ctx context.Context) ([]byte, error) { } // translate the int returned from bond mode metadata to the type needed by networkd - bondMode := nic.BondMode(uint8(unmarshalledMetadataConfig.Network.Bonding.Mode)) + bondMode := nethelpers.BondMode(uint8(unmarshalledMetadataConfig.Network.Bonding.Mode)) // determine bond name and build list of interfaces enslaved by the bond devicesInBond := []string{} diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go index 4558c4f79..a3546b4db 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go @@ -64,7 +64,6 @@ func (*Sequencer) ApplyConfiguration(r runtime.Runtime, req *machineapi.ApplyCon ).Append( "cleanup", StopAllPods, - StopNetworkd, ).AppendList( stopAllPhaselist(r), ).Append( @@ -114,11 +113,7 @@ func (*Sequencer) Initialize(r runtime.Runtime) []runtime.Phase { WriteIMAPolicy, ).Append( "etc", - CreateEtcNetworkFiles, CreateOSReleaseFile, - ).Append( - "discoverNetwork", - SetupDiscoveryNetwork, ).AppendWhen( r.State().Machine().Installed(), "mountSystem", @@ -130,12 +125,6 @@ func (*Sequencer) Initialize(r runtime.Runtime) []runtime.Phase { r.State().Machine().Installed(), "unmountSystem", UnmountStatePartition, - ).Append( - "resetNetwork", - ResetNetwork, - ).Append( - "setupNetwork", - SetupDiscoveryNetwork, ) } @@ -287,7 +276,6 @@ func (*Sequencer) Reboot(r runtime.Runtime) []runtime.Phase { phases := PhaseList{}.Append( "cleanup", StopAllPods, - StopNetworkd, ). AppendList(stopAllPhaselist(r)). Append("reboot", Reboot) @@ -315,12 +303,10 @@ func (*Sequencer) Reset(r runtime.Runtime, in runtime.ResetOptions) []runtime.Ph in.GetGraceful(), "cleanup", RemoveAllPods, - StopNetworkd, ).AppendWhen( !in.GetGraceful(), "cleanup", StopAllPods, - StopNetworkd, ).AppendWhen( in.GetGraceful() && (r.Config().Machine().Type() != machine.TypeJoin), "leave", @@ -355,7 +341,6 @@ func (*Sequencer) Shutdown(r runtime.Runtime) []runtime.Phase { Append( "cleanup", StopAllPods, - StopNetworkd, ). AppendList(stopAllPhaselist(r)). Append("shutdown", Shutdown) @@ -374,7 +359,6 @@ func (*Sequencer) StageUpgrade(r runtime.Runtime, in *machineapi.UpgradeRequest) phases = phases.Append( "cleanup", StopAllPods, - StopNetworkd, ).AppendWhen( !in.GetPreserve() && (r.Config().Machine().Type() != machine.TypeJoin), "leave", @@ -405,12 +389,10 @@ func (*Sequencer) Upgrade(r runtime.Runtime, in *machineapi.UpgradeRequest) []ru !in.GetPreserve(), "cleanup", RemoveAllPods, - StopNetworkd, ).AppendWhen( in.GetPreserve(), "cleanup", StopAllPods, - StopNetworkd, ).AppendWhen( !in.GetPreserve() && (r.Config().Machine().Type() != machine.TypeJoin), "leave", diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go index 57b5d7432..853ee822c 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go @@ -48,7 +48,6 @@ import ( "github.com/talos-systems/talos/internal/app/machined/pkg/system/events" "github.com/talos-systems/talos/internal/app/machined/pkg/system/services" "github.com/talos-systems/talos/internal/app/maintenance" - "github.com/talos-systems/talos/internal/app/networkd/pkg/networkd" "github.com/talos-systems/talos/internal/pkg/containers/cri/containerd" "github.com/talos-systems/talos/internal/pkg/cri" "github.com/talos-systems/talos/internal/pkg/etcd" @@ -307,16 +306,6 @@ HOME_URL="https://docs.talos-systems.com/" BUG_REPORT_URL="https://github.com/talos-systems/talos/issues" ` -// Hosts creates a persistent and writable /etc/hosts file. -func Hosts() (err error) { - return createBindMount(filepath.Join(constants.SystemEtcPath, "hosts"), "/etc/hosts") -} - -// ResolvConf creates a persistent and writable /etc/resolv.conf file. -func ResolvConf() (err error) { - return createBindMount(filepath.Join(constants.SystemEtcPath, "resolv.conf"), "/etc/resolv.conf") -} - // OSRelease renders a valid /etc/os-release file and writes it to disk. The // node's OS Image field is reported by the node from /etc/os-release. func OSRelease() (err error) { @@ -384,19 +373,6 @@ func createBindMount(src, dst string) (err error) { return nil } -// CreateEtcNetworkFiles represents the CreateEtcNetworkFiles task. -func CreateEtcNetworkFiles(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { - return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - // Create /etc/resolv.conf. - if err = ResolvConf(); err != nil { - return err - } - - // Create /etc/hosts - return Hosts() - }, "createEtcNetworkFiles" -} - // CreateOSReleaseFile represents the CreateOSReleaseFile task. func CreateOSReleaseFile(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { @@ -405,21 +381,6 @@ func CreateOSReleaseFile(seq runtime.Sequence, data interface{}) (runtime.TaskEx }, "createOSReleaseFile" } -// SetupDiscoveryNetwork represents the task for setting up the initial network. -func SetupDiscoveryNetwork(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { - return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - nwd, err := networkd.New(logger, r.Config()) - if err != nil { - return err - } - - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - return nwd.Configure(ctx) - }, "setupDiscoveryNetwork" -} - // LoadConfig represents the LoadConfig task. func LoadConfig(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { @@ -568,20 +529,6 @@ func ValidateConfig(seq runtime.Sequence, data interface{}) (runtime.TaskExecuti }, "validateConfig" } -// ResetNetwork resets the network. -func ResetNetwork(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { - return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - nwd, err := networkd.New(logger, r.Config()) - if err != nil { - return err - } - - nwd.Reset() - - return nil - }, "resetNetwork" -} - // SetUserEnvVars represents the SetUserEnvVars task. func SetUserEnvVars(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { @@ -630,7 +577,6 @@ func StartAllServices(seq runtime.Sequence, data interface{}) (runtime.TaskExecu svcs.Load( &services.APID{}, - &services.Networkd{}, &services.CRI{}, &services.Kubelet{}, ) @@ -669,14 +615,6 @@ func StartAllServices(seq runtime.Sequence, data interface{}) (runtime.TaskExecu }, "startAllServices" } -// StopNetworkd represents the StopNetworkd task. -func StopNetworkd(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { - return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - // stop networkd so that it gives up on VIP lease - return system.Services(nil).Stop(ctx, "networkd") - }, "stopNetworkd" -} - // StopServicesForUpgrade represents the StopServicesForUpgrade task. func StopServicesForUpgrade(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go index db5b276a6..0b0b95f97 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go @@ -77,21 +77,20 @@ func (ctrl *Controller) Run(ctx context.Context) error { &k8s.ManifestApplyController{}, &k8s.RenderSecretsStaticPodController{}, &network.AddressConfigController{ - Cmdline: procfs.ProcCmdline(), + Cmdline: procfs.ProcCmdline(), + V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(), }, &network.AddressMergeController{}, &network.AddressSpecController{}, &network.AddressStatusController{}, - // TODO: disabled to avoid conflict with networkd - // &network.EtcFileController{}, + &network.EtcFileController{}, &network.HostnameConfigController{ Cmdline: procfs.ProcCmdline(), }, &network.HostnameMergeController{}, - // TODO: disabled to avoid conflict with networkd - // &network.HostnameSpecController{ - // V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(), - // }, + &network.HostnameSpecController{ + V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(), + }, &network.LinkConfigController{ Cmdline: procfs.ProcCmdline(), }, @@ -102,6 +101,13 @@ func (ctrl *Controller) Run(ctx context.Context) error { &network.OperatorConfigController{ Cmdline: procfs.ProcCmdline(), }, + &network.OperatorSpecController{ + V1alpha1Platform: ctrl.v1alpha1Runtime.State().Platform(), + State: ctrl.v1alpha1Runtime.State().V1Alpha2().Resources(), + }, + &network.PlatformConfigController{ + V1alpha1Platform: ctrl.v1alpha1Runtime.State().Platform(), + }, &network.ResolverConfigController{ Cmdline: procfs.ProcCmdline(), }, diff --git a/internal/app/machined/pkg/system/services/apid.go b/internal/app/machined/pkg/system/services/apid.go index 04d77a9c0..c34aa9027 100644 --- a/internal/app/machined/pkg/system/services/apid.go +++ b/internal/app/machined/pkg/system/services/apid.go @@ -31,6 +31,7 @@ import ( "github.com/talos-systems/talos/pkg/copy" "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/talos-systems/talos/pkg/machinery/constants" + "github.com/talos-systems/talos/pkg/resources/network" "github.com/talos-systems/talos/pkg/resources/time" ) @@ -71,6 +72,7 @@ func (o *APID) PostFunc(r runtime.Runtime, state events.ServiceState) (err error func (o *APID) Condition(r runtime.Runtime) conditions.Condition { conds := []conditions.Condition{ time.NewSyncCondition(r.State().V1Alpha2().Resources()), + network.NewReadyCondition(r.State().V1Alpha2().Resources(), network.AddressReady, network.HostnameReady), } if r.Config().Machine().Type() == machine.TypeJoin { @@ -82,7 +84,7 @@ func (o *APID) Condition(r runtime.Runtime) conditions.Condition { // DependsOn implements the Service interface. func (o *APID) DependsOn(r runtime.Runtime) []string { - return []string{"containerd", "networkd"} + return []string{"containerd"} } // Runner implements the Service interface. diff --git a/internal/app/machined/pkg/system/services/cri.go b/internal/app/machined/pkg/system/services/cri.go index 8407dfe02..2f0c9d2d9 100644 --- a/internal/app/machined/pkg/system/services/cri.go +++ b/internal/app/machined/pkg/system/services/cri.go @@ -21,6 +21,7 @@ import ( "github.com/talos-systems/talos/internal/app/machined/pkg/system/runner/restart" "github.com/talos-systems/talos/pkg/conditions" "github.com/talos-systems/talos/pkg/machinery/constants" + "github.com/talos-systems/talos/pkg/resources/network" ) // CRI implements the Service interface. It serves as the concrete type with @@ -44,12 +45,12 @@ func (c *CRI) PostFunc(r runtime.Runtime, state events.ServiceState) (err error) // Condition implements the Service interface. func (c *CRI) Condition(r runtime.Runtime) conditions.Condition { - return nil + return network.NewReadyCondition(r.State().V1Alpha2().Resources(), network.AddressReady, network.HostnameReady, network.EtcFilesReady) } // DependsOn implements the Service interface. func (c *CRI) DependsOn(r runtime.Runtime) []string { - return []string{"networkd"} + return nil } // Runner implements the Service interface. diff --git a/internal/app/machined/pkg/system/services/etcd.go b/internal/app/machined/pkg/system/services/etcd.go index 8bec42b36..f5eed7590 100644 --- a/internal/app/machined/pkg/system/services/etcd.go +++ b/internal/app/machined/pkg/system/services/etcd.go @@ -40,6 +40,7 @@ import ( "github.com/talos-systems/talos/pkg/conditions" "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" "github.com/talos-systems/talos/pkg/machinery/constants" + "github.com/talos-systems/talos/pkg/resources/network" timeresource "github.com/talos-systems/talos/pkg/resources/time" ) @@ -113,12 +114,15 @@ func (e *Etcd) PostFunc(r runtime.Runtime, state events.ServiceState) (err error // Condition implements the Service interface. func (e *Etcd) Condition(r runtime.Runtime) conditions.Condition { - return timeresource.NewSyncCondition(r.State().V1Alpha2().Resources()) + return conditions.WaitForAll( + timeresource.NewSyncCondition(r.State().V1Alpha2().Resources()), + network.NewReadyCondition(r.State().V1Alpha2().Resources(), network.AddressReady, network.HostnameReady, network.EtcFilesReady), + ) } // DependsOn implements the Service interface. func (e *Etcd) DependsOn(r runtime.Runtime) []string { - return []string{"cri", "networkd"} + return []string{"cri"} } // Runner implements the Service interface. diff --git a/internal/app/machined/pkg/system/services/kubelet.go b/internal/app/machined/pkg/system/services/kubelet.go index 3fb1ee14e..9cf7475c7 100644 --- a/internal/app/machined/pkg/system/services/kubelet.go +++ b/internal/app/machined/pkg/system/services/kubelet.go @@ -35,6 +35,7 @@ import ( "github.com/talos-systems/talos/pkg/argsbuilder" "github.com/talos-systems/talos/pkg/conditions" "github.com/talos-systems/talos/pkg/machinery/constants" + "github.com/talos-systems/talos/pkg/resources/network" timeresource "github.com/talos-systems/talos/pkg/resources/time" ) @@ -127,12 +128,15 @@ func (k *Kubelet) PostFunc(r runtime.Runtime, state events.ServiceState) (err er // Condition implements the Service interface. func (k *Kubelet) Condition(r runtime.Runtime) conditions.Condition { - return timeresource.NewSyncCondition(r.State().V1Alpha2().Resources()) + return conditions.WaitForAll( + timeresource.NewSyncCondition(r.State().V1Alpha2().Resources()), + network.NewReadyCondition(r.State().V1Alpha2().Resources(), network.AddressReady, network.HostnameReady, network.EtcFilesReady), + ) } // DependsOn implements the Service interface. func (k *Kubelet) DependsOn(r runtime.Runtime) []string { - return []string{"cri", "networkd"} + return []string{"cri"} } // Runner implements the Service interface. diff --git a/internal/app/machined/pkg/system/services/networkd.go b/internal/app/machined/pkg/system/services/networkd.go deleted file mode 100644 index ffc1479b8..000000000 --- a/internal/app/machined/pkg/system/services/networkd.go +++ /dev/null @@ -1,123 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -//nolint:golint -package services - -import ( - "context" - "errors" - "fmt" - "log" - "os" - "path/filepath" - - "github.com/golang/protobuf/ptypes/empty" - "google.golang.org/grpc" - - "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" - "github.com/talos-systems/talos/internal/app/machined/pkg/system/events" - "github.com/talos-systems/talos/internal/app/machined/pkg/system/health" - "github.com/talos-systems/talos/internal/app/machined/pkg/system/runner" - "github.com/talos-systems/talos/internal/app/machined/pkg/system/runner/goroutine" - "github.com/talos-systems/talos/internal/app/machined/pkg/system/runner/restart" - "github.com/talos-systems/talos/internal/app/networkd" - "github.com/talos-systems/talos/pkg/conditions" - "github.com/talos-systems/talos/pkg/grpc/dialer" - healthapi "github.com/talos-systems/talos/pkg/machinery/api/health" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -// Networkd implements the Service interface. It serves as the concrete type with -// the required methods. -type Networkd struct{} - -// ID implements the Service interface. -func (n *Networkd) ID(r runtime.Runtime) string { - return "networkd" -} - -// PreFunc implements the Service interface. -func (n *Networkd) PreFunc(ctx context.Context, r runtime.Runtime) error { - return os.MkdirAll(filepath.Dir(constants.NetworkSocketPath), 0o750) -} - -// PostFunc implements the Service interface. -func (n *Networkd) PostFunc(r runtime.Runtime, state events.ServiceState) (err error) { - return nil -} - -// Condition implements the Service interface. -func (n *Networkd) Condition(r runtime.Runtime) conditions.Condition { - return nil -} - -// DependsOn implements the Service interface. -func (n *Networkd) DependsOn(r runtime.Runtime) []string { - return nil -} - -func (n *Networkd) Runner(r runtime.Runtime) (runner.Runner, error) { - return restart.New(goroutine.NewRunner( - r, - "networkd", - networkd.Main, - runner.WithLoggingManager(r.Logging()), - ), - restart.WithType(restart.Forever), - ), nil -} - -// HealthFunc implements the HealthcheckedService interface. -func (n *Networkd) HealthFunc(r runtime.Runtime) health.Check { - return func(ctx context.Context) error { - var ( - conn *grpc.ClientConn - err error - hcResp *healthapi.HealthCheckResponse - readyResp *healthapi.ReadyCheckResponse - ) - - conn, err = grpc.DialContext( - ctx, - fmt.Sprintf("%s://%s", "unix", constants.NetworkSocketPath), - grpc.WithInsecure(), - grpc.WithContextDialer(dialer.DialUnix()), - ) - if err != nil { - return err - } - defer conn.Close() //nolint:errcheck - - nClient := healthapi.NewHealthClient(conn) - if readyResp, err = nClient.Ready(ctx, &empty.Empty{}); err != nil { - return err - } - - if readyResp.Messages[0].Status != healthapi.ReadyCheck_READY { - return errors.New("networkd is not ready") - } - - if hcResp, err = nClient.Check(ctx, &empty.Empty{}); err != nil { - return err - } - - if hcResp.Messages[0].Status == healthapi.HealthCheck_SERVING { - return nil - } - - msg := fmt.Sprintf("networkd is unhealthy: %s", hcResp.Messages[0].Status.String()) - - if r.Config().Debug() { - log.Printf("DEBUG: %s", msg) - } - - return errors.New(msg) - } -} - -// HealthSettings implements the HealthcheckedService interface. -func (n *Networkd) HealthSettings(runtime.Runtime) *health.Settings { - return &health.DefaultSettings -} diff --git a/internal/app/machined/pkg/system/services/networkd_test.go b/internal/app/machined/pkg/system/services/networkd_test.go deleted file mode 100644 index 142e0869b..000000000 --- a/internal/app/machined/pkg/system/services/networkd_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package services_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/talos-systems/talos/internal/app/machined/pkg/system" - "github.com/talos-systems/talos/internal/app/machined/pkg/system/services" -) - -func TestNetworkdInterfaces(t *testing.T) { - assert.Implements(t, (*system.HealthcheckedService)(nil), new(services.Networkd)) -} diff --git a/internal/app/machined/pkg/system/services/trustd.go b/internal/app/machined/pkg/system/services/trustd.go index 4af74c1e8..2c2a8b7a8 100644 --- a/internal/app/machined/pkg/system/services/trustd.go +++ b/internal/app/machined/pkg/system/services/trustd.go @@ -24,6 +24,7 @@ import ( "github.com/talos-systems/talos/internal/app/machined/pkg/system/runner/restart" "github.com/talos-systems/talos/pkg/conditions" "github.com/talos-systems/talos/pkg/machinery/constants" + "github.com/talos-systems/talos/pkg/resources/network" timeresource "github.com/talos-systems/talos/pkg/resources/time" ) @@ -48,12 +49,15 @@ func (t *Trustd) PostFunc(r runtime.Runtime, state events.ServiceState) (err err // Condition implements the Service interface. func (t *Trustd) Condition(r runtime.Runtime) conditions.Condition { - return timeresource.NewSyncCondition(r.State().V1Alpha2().Resources()) + return conditions.WaitForAll( + timeresource.NewSyncCondition(r.State().V1Alpha2().Resources()), + network.NewReadyCondition(r.State().V1Alpha2().Resources(), network.AddressReady, network.HostnameReady), + ) } // DependsOn implements the Service interface. func (t *Trustd) DependsOn(r runtime.Runtime) []string { - return []string{"containerd", "networkd"} + return []string{"containerd"} } func (t *Trustd) Runner(r runtime.Runtime) (runner.Runner, error) { diff --git a/internal/app/networkd/main.go b/internal/app/networkd/main.go deleted file mode 100644 index d9ca5131c..000000000 --- a/internal/app/networkd/main.go +++ /dev/null @@ -1,79 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package networkd - -import ( - "context" - "io" - "log" - - "golang.org/x/sync/errgroup" - - "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" - "github.com/talos-systems/talos/internal/app/networkd/pkg/networkd" - "github.com/talos-systems/talos/internal/app/networkd/pkg/reg" - "github.com/talos-systems/talos/pkg/grpc/factory" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -// Main is the entrypoint into networkd. -func Main(ctx context.Context, r runtime.Runtime, logOutput io.Writer) error { - logger := log.New(logOutput, "", log.Lshortfile|log.Ldate|log.Lmicroseconds|log.Ltime) - - defer logger.Println("networkd stopped") - - return run(ctx, r, logger) -} - -func run(ctx context.Context, r runtime.Runtime, logger *log.Logger) error { - var eg errgroup.Group - - logger.Println("starting initial network configuration") - - nwd, err := networkd.New(logger, r.Config()) - if err != nil { - return err - } - - if err = nwd.Configure(ctx); err != nil { - return err - } - - registrator, err := reg.NewRegistrator(nwd) - if err != nil { - return err - } - - if err = nwd.RunControllers(ctx, &eg); err != nil { - return err - } - - logger.Println("completed initial network configuration") - - nwd.Renew(ctx) - - server := factory.NewServer( - registrator, - factory.WithLog("", logger.Writer()), - ) - - listener, err := factory.NewListener( - factory.Network("unix"), - factory.SocketPath(constants.NetworkSocketPath), - ) - if err != nil { - return err - } - - eg.Go(func() error { - return server.Serve(listener) - }) - - <-ctx.Done() - - server.GracefulStop() - - return eg.Wait() -} diff --git a/internal/app/networkd/pkg/address/address.go b/internal/app/networkd/pkg/address/address.go deleted file mode 100644 index f72b73157..000000000 --- a/internal/app/networkd/pkg/address/address.go +++ /dev/null @@ -1,49 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package address - -import ( - "context" - "log" - "net" - "time" -) - -// Addressing provides an interface for abstracting the underlying network -// addressing configuration. Currently dhcp(v4) and static methods are -// supported. -type Addressing interface { - Address() *net.IPNet - Discover(context.Context, *log.Logger, *net.Interface) error - Family() int - Hostname() string - Link() *net.Interface - MTU() uint32 - Mask() net.IPMask - Name() string - Resolvers() []net.IP - Routes() []*Route - Scope() uint8 - TTL() time.Duration - Valid() bool -} - -// Route is a representation of a network route. -type Route struct { - // Destination is the destination network this route provides. - Destination *net.IPNet - - // Gateway is the router through which the destination may be reached. - // This option is exclusive of Interface - Gateway net.IP - - // Interface indicates the route is an interface route, and traffic destinted for the Gateway should be sent through the given network interface. - // This option is exclusive of Gateway. - Interface string - - // Metric indicates the "distance" to the destination through this route. - // This is an integer which allows the control of priority in the case of multiple routes to the same destination. - Metric uint32 -} diff --git a/internal/app/networkd/pkg/address/dhcp4.go b/internal/app/networkd/pkg/address/dhcp4.go deleted file mode 100644 index 0aaf89b19..000000000 --- a/internal/app/networkd/pkg/address/dhcp4.go +++ /dev/null @@ -1,273 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package address - -import ( - "context" - "fmt" - "log" - "net" - "strings" - "time" - - "github.com/insomniacslk/dhcp/dhcpv4" - "github.com/insomniacslk/dhcp/dhcpv4/nclient4" - "github.com/talos-systems/go-procfs/procfs" - "golang.org/x/sys/unix" - - "github.com/talos-systems/talos/pkg/machinery/config" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -const dhcpReceivedRouteMetric uint32 = 1024 - -// DHCP4 implements the Addressing interface. -type DHCP4 struct { - Offer *dhcpv4.DHCPv4 - Ack *dhcpv4.DHCPv4 - NetIf *net.Interface - DHCPOptions config.DHCPOptions - Mtu int - RouteList []config.Route -} - -// Name returns back the name of the address method. -func (d *DHCP4) Name() string { - return "dhcp4" -} - -// Link returns the underlying net.Interface that this address -// method is configured for. -func (d *DHCP4) Link() *net.Interface { - return d.NetIf -} - -// Discover handles the DHCP client exchange stores the DHCP Ack. -func (d *DHCP4) Discover(ctx context.Context, logger *log.Logger, link *net.Interface) error { - d.NetIf = link - err := d.discover(ctx, logger) - - return err -} - -// Address returns back the IP address from the received DHCP offer. -func (d *DHCP4) Address() *net.IPNet { - return &net.IPNet{ - IP: d.Ack.YourIPAddr, - Mask: d.Mask(), - } -} - -// Mask returns the netmask from the DHCP offer. -func (d *DHCP4) Mask() net.IPMask { - return d.Ack.SubnetMask() -} - -// MTU returs the MTU size from the DHCP offer. -func (d *DHCP4) MTU() uint32 { - mtuReturn := uint32(d.NetIf.MTU) - - if d.Ack != nil { - // TODO do we need to implement dhcpv4.GetUint32 upstream? - mtu, err := dhcpv4.GetUint16(dhcpv4.OptionInterfaceMTU, d.Ack.Options) - if err == nil { - mtuReturn = uint32(mtu) - } - } - - // override with any non-zero Mtu value passed into the dhcp object - if uint32(d.Mtu) > 0 { - mtuReturn = uint32(d.Mtu) - } - - return mtuReturn -} - -// TTL denotes how long a DHCP offer is valid for. -func (d *DHCP4) TTL() time.Duration { - if d.Ack == nil { - return 0 - } - - return d.Ack.IPAddressLeaseTime(time.Minute * 30) -} - -// Family qualifies the address as ipv4 or ipv6. -func (d *DHCP4) Family() int { - return unix.AF_INET -} - -// Scope sets the address scope. -func (d *DHCP4) Scope() uint8 { - return unix.RT_SCOPE_UNIVERSE -} - -// Valid denotes if this address method should be used. -func (d *DHCP4) Valid() bool { - return d.Ack != nil -} - -// Routes aggregates all Routers and ClasslessStaticRoutes retrieved from -// the DHCP offer. -// rfc3442: -// If the DHCP server returns both a Classless Static Routes option and -// a Router option, the DHCP client MUST ignore the Router option. -func (d *DHCP4) Routes() (routes []*Route) { - metric := dhcpReceivedRouteMetric - - if d.DHCPOptions != nil && d.DHCPOptions.RouteMetric() != 0 { - metric = d.DHCPOptions.RouteMetric() - } - - defRoute := &net.IPNet{ - IP: net.IPv4zero, - Mask: net.IPv4Mask(0, 0, 0, 0), - } - - for _, router := range d.Ack.Router() { - routes = append(routes, &Route{ - Destination: defRoute, - Gateway: router, - Metric: metric, - }) - } - - // overwrite router option if classless routes were provided. - if len(d.Ack.ClasslessStaticRoute()) > 0 { - routes = []*Route{} - - for _, dhcpRoute := range d.Ack.ClasslessStaticRoute() { - routes = append(routes, &Route{ - Destination: dhcpRoute.Dest, - Gateway: dhcpRoute.Router, - Metric: metric, - }) - } - } - - // append any routes that were provided in config - for _, route := range d.RouteList { - _, ipnet, err := net.ParseCIDR(route.Network()) - if err != nil { - // TODO: we should at least log this failure - continue - } - - routes = append(routes, &Route{ - Destination: ipnet, - Gateway: net.ParseIP(route.Gateway()), - Metric: staticRouteDefaultMetric, - }) - } - - return routes -} - -// Resolvers returns the DNS resolvers from the DHCP offer. -func (d *DHCP4) Resolvers() []net.IP { - return d.Ack.DNS() -} - -// Hostname returns the hostname from the DHCP offer. -func (d *DHCP4) Hostname() (hostname string) { - if d.Ack.HostName() == "" { - hostname = fmt.Sprintf("%s-%s", "talos", strings.ReplaceAll(d.Address().IP.String(), ".", "-")) - } else { - hostname = d.Ack.HostName() - } - - if d.Ack.DomainName() != "" { - hostname = fmt.Sprintf("%s.%s", strings.Split(hostname, ".")[0], d.Ack.DomainName()) - } - - return hostname -} - -// discover handles the actual DHCP conversation. -func (d *DHCP4) discover(ctx context.Context, logger *log.Logger) error { - opts := []dhcpv4.OptionCode{ - dhcpv4.OptionClasslessStaticRoute, - dhcpv4.OptionDomainNameServer, - dhcpv4.OptionDNSDomainSearchList, - dhcpv4.OptionHostName, - // TODO: handle these options - dhcpv4.OptionNTPServers, - dhcpv4.OptionDomainName, - } - - // <3 azure - // When including dhcp.OptionInterfaceMTU we don't get a dhcp offer back on azure. - // So we'll need to explicitly exclude adding this option for azure. - if p := procfs.ProcCmdline().Get(constants.KernelParamPlatform).First(); p != nil { - if *p != "azure" { - opts = append(opts, dhcpv4.OptionInterfaceMTU) - } - } - - mods := []dhcpv4.Modifier{dhcpv4.WithRequestedOptions(opts...)} - clientOpts := []nclient4.ClientOpt{} - - if d.Offer != nil { - // do not use broadcast, but send the packet to DHCP server directly - addr, err := net.ResolveUDPAddr("udp", d.Offer.ServerIPAddr.String()+":67") - if err != nil { - return err - } - - // by default it's set to 0.0.0.0 which actually breaks lease renew - d.Offer.ClientIPAddr = d.Offer.YourIPAddr - - clientOpts = append(clientOpts, nclient4.WithServerAddr(addr)) - } - - // TODO expose this ( nclient4.WithDebugLogger() ) with some - // debug logging option - cli, err := nclient4.New(d.NetIf.Name, clientOpts...) - if err != nil { - return err - } - - //nolint:errcheck - defer cli.Close() - - var lease *nclient4.Lease - - if d.Offer != nil { - lease, err = cli.RequestFromOffer(ctx, d.Offer, mods...) - } else { - lease, err = cli.Request(ctx, mods...) - } - - if err != nil { - // TODO: Make this a well defined error so we can make it not fatal - logger.Printf("failed dhcp request for %q: %v", d.NetIf.Name, err) - - // clear offer if request fails to start with discover sequence next time - d.Offer = nil - - return err - } - - logger.Printf("DHCP ACK on %q: %s", d.NetIf.Name, collapseSummary(lease.ACK.Summary())) - - d.Ack = lease.ACK - d.Offer = lease.Offer - - return err -} - -func collapseSummary(summary string) string { - lines := strings.Split(summary, "\n")[1:] - - for i := range lines { - lines[i] = strings.TrimSpace(lines[i]) - } - - if len(lines) > 0 && lines[len(lines)-1] == "" { - lines = lines[:len(lines)-1] - } - - return strings.Join(lines, ", ") -} diff --git a/internal/app/networkd/pkg/address/dhcp6.go b/internal/app/networkd/pkg/address/dhcp6.go deleted file mode 100644 index 9dcc1765a..000000000 --- a/internal/app/networkd/pkg/address/dhcp6.go +++ /dev/null @@ -1,203 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package address - -import ( - "context" - "fmt" - "log" - "net" - "strings" - "time" - - "github.com/insomniacslk/dhcp/dhcpv6" - "github.com/insomniacslk/dhcp/dhcpv6/nclient6" - "github.com/jsimonetti/rtnetlink" - "github.com/talos-systems/go-retry/retry" - "golang.org/x/sys/unix" -) - -// DHCP6 implements the Addressing interface. -type DHCP6 struct { - Reply *dhcpv6.Message - NetIf *net.Interface - Mtu int -} - -// Name returns back the name of the address method. -func (d *DHCP6) Name() string { - return "dhcp6" -} - -// Link returns the underlying net.Interface that this address -// method is configured for. -func (d *DHCP6) Link() *net.Interface { - return d.NetIf -} - -// Discover handles the DHCP client exchange stores the DHCP Ack. -func (d *DHCP6) Discover(ctx context.Context, logger *log.Logger, link *net.Interface) error { - d.NetIf = link - err := d.discover(ctx, logger) - - return err -} - -// Address returns back the IP address from the received DHCP offer. -func (d *DHCP6) Address() *net.IPNet { - if d.Reply.Options.OneIANA() == nil { - return nil - } - - return &net.IPNet{ - IP: d.Reply.Options.OneIANA().Options.OneAddress().IPv6Addr, - Mask: net.CIDRMask(128, 128), - } -} - -// Mask returns the netmask from the DHCP offer. -func (d *DHCP6) Mask() net.IPMask { - return net.CIDRMask(128, 128) -} - -// MTU returs the MTU size from the DHCP offer. -func (d *DHCP6) MTU() uint32 { - if d.Mtu > 0 { - return uint32(d.Mtu) - } - - return uint32(d.NetIf.MTU) -} - -// TTL denotes how long a DHCP offer is valid for. -func (d *DHCP6) TTL() time.Duration { - if d.Reply == nil { - return 0 - } - - return d.Reply.Options.OneIANA().Options.OneAddress().ValidLifetime -} - -// Family qualifies the address as ipv4 or ipv6. -func (d *DHCP6) Family() int { - return unix.AF_INET6 -} - -// Scope sets the address scope. -func (d *DHCP6) Scope() uint8 { - return unix.RT_SCOPE_UNIVERSE -} - -// Valid denotes if this address method should be used. -func (d *DHCP6) Valid() bool { - return d.Reply != nil && d.Reply.Options.OneIANA() != nil -} - -// Routes is not supported on IPv6. -func (d *DHCP6) Routes() (routes []*Route) { - return nil -} - -// Resolvers returns the DNS resolvers from the DHCP offer. -func (d *DHCP6) Resolvers() []net.IP { - return d.Reply.Options.DNS() -} - -// Hostname returns the hostname from the DHCP offer. -func (d *DHCP6) Hostname() (hostname string) { - fqdn := d.Reply.Options.FQDN() - - if fqdn != nil && fqdn.DomainName != nil { - hostname = strings.Join(fqdn.DomainName.Labels, ".") - } else { - hostname = fmt.Sprintf("%s-%s", "talos", strings.ReplaceAll(d.Address().IP.String(), ":", "")) - } - - return hostname -} - -// discover handles the actual DHCP conversation. -func (d *DHCP6) discover(ctx context.Context, logger *log.Logger) error { - if err := waitIPv6LinkReady(logger, d.NetIf); err != nil { - logger.Printf("failed waiting for IPv6 readiness: %s", err) - - return err - } - - cli, err := nclient6.New(d.NetIf.Name) - if err != nil { - logger.Printf("failed to create dhcp6 client: %s", err) - - return err - } - - //nolint:errcheck - defer cli.Close() - - reply, err := cli.RapidSolicit(ctx) - if err != nil { - // TODO: Make this a well defined error so we can make it not fatal - logger.Printf("failed dhcp6 request for %q: %v", d.NetIf.Name, err) - - return err - } - - logger.Printf("DHCP6 REPLY on %q: %s", d.NetIf.Name, collapseSummary(reply.Summary())) - - d.Reply = reply - - return nil -} - -func waitIPv6LinkReady(logger *log.Logger, iface *net.Interface) error { - conn, err := rtnetlink.Dial(nil) - if err != nil { - return err - } - - defer conn.Close() //nolint:errcheck - - return retry.Constant(30*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error { - ready, err := isIPv6LinkReady(logger, iface, conn) - if err != nil { - return err - } - - if !ready { - return retry.ExpectedError(fmt.Errorf("IPv6 address is still tentative")) - } - - return nil - }) -} - -// isIPv6LinkReady returns true if the interface has a link-local address -// which is not tentative. -func isIPv6LinkReady(logger *log.Logger, iface *net.Interface, conn *rtnetlink.Conn) (bool, error) { - addrs, err := conn.Address.List() - if err != nil { - return false, err - } - - for _, addr := range addrs { - if addr.Index != uint32(iface.Index) { - continue - } - - if addr.Family != unix.AF_INET6 { - continue - } - - if addr.Attributes.Address.IsLinkLocalUnicast() && (addr.Flags&unix.IFA_F_TENTATIVE == 0) { - if addr.Flags&unix.IFA_F_DADFAILED != 0 { - logger.Printf("DADFAILED for %v, continuing anyhow", addr.Attributes.Address) - } - - return true, nil - } - } - - return false, nil -} diff --git a/internal/app/networkd/pkg/address/static.go b/internal/app/networkd/pkg/address/static.go deleted file mode 100644 index ac2487a9f..000000000 --- a/internal/app/networkd/pkg/address/static.go +++ /dev/null @@ -1,145 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package address - -import ( - "context" - "log" - "net" - "time" - - "golang.org/x/sys/unix" - - "github.com/talos-systems/talos/pkg/machinery/config" -) - -const staticRouteDefaultMetric uint32 = 10 - -// Static implements the Addressing interface. -type Static struct { - CIDR string - Mtu int - FQDN string - RouteList []config.Route - NetIf *net.Interface - NameServers []net.IP -} - -// Discover doesnt do anything in the static configuration since all -// the necessary configuration data is supplied via config. -func (s *Static) Discover(ctx context.Context, logger *log.Logger, link *net.Interface) error { - s.NetIf = link - - return nil -} - -// Name returns back the name of the address method. -func (s *Static) Name() string { - return "static" -} - -// Address returns the IP address. -func (s *Static) Address() *net.IPNet { - var ip net.IP - - var ipn *net.IPNet - - if s.CIDR != "" { - //nolint:errcheck - ip, ipn, _ = net.ParseCIDR(s.CIDR) - ipn.IP = ip - } - - return ipn -} - -// Mask returns the netmask. -func (s *Static) Mask() net.IPMask { - //nolint:errcheck - _, ipnet, _ := net.ParseCIDR(s.CIDR) - - return ipnet.Mask -} - -// MTU returns the specified MTU. -func (s *Static) MTU() uint32 { - mtu := uint32(s.Mtu) - if mtu == 0 { - mtu = uint32(s.NetIf.MTU) - } - - return mtu -} - -// TTL returns the address lifetime. Since this is static, there is -// no TTL (0). -func (s *Static) TTL() time.Duration { - return 0 -} - -// Family qualifies the address as ipv4 or ipv6. -func (s *Static) Family() int { - if s.Address() == nil { - panic("unable to determine address family as address is nil") - } - - if s.Address().IP.To4() != nil { - return unix.AF_INET - } - - return unix.AF_INET6 -} - -// Scope sets the address scope. -func (s *Static) Scope() uint8 { - return unix.RT_SCOPE_UNIVERSE -} - -// Routes aggregates the specified routes for a given device configuration -// TODO: do we need to be explicit on route vs gateway? -func (s *Static) Routes() (routes []*Route) { - for _, route := range s.RouteList { - _, ipnet, err := net.ParseCIDR(route.Network()) - if err != nil { - // TODO: we should at least log the error - continue - } - - metric := staticRouteDefaultMetric - - if route.Metric() != 0 { - metric = route.Metric() - } - - routes = append(routes, &Route{ - Destination: ipnet, - Gateway: net.ParseIP(route.Gateway()), - Metric: metric, - }) - } - - return routes -} - -// Resolvers returns the DNS resolvers. -func (s *Static) Resolvers() []net.IP { - return s.NameServers -} - -// Hostname returns the hostname. -func (s *Static) Hostname() string { - return s.FQDN -} - -// Link returns the underlying net.Interface that this address -// method is configured for. -func (s Static) Link() *net.Interface { - return s.NetIf -} - -// Valid denotes if this address method should be used. -func (s *Static) Valid() bool { - return true -} diff --git a/internal/app/networkd/pkg/networkd/misc.go b/internal/app/networkd/pkg/networkd/misc.go deleted file mode 100644 index 3cbaf1d8e..000000000 --- a/internal/app/networkd/pkg/networkd/misc.go +++ /dev/null @@ -1,154 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package networkd - -import ( - "bytes" - "fmt" - "io/ioutil" - "log" - "net" - "strings" - "text/template" - - "github.com/jsimonetti/rtnetlink" - talosnet "github.com/talos-systems/net" - "golang.org/x/sys/unix" - - "github.com/talos-systems/talos/pkg/machinery/config" -) - -// filterInterfaces filters network links by name so we only mange links -// we need to. -// -//nolint:gocyclo -func filterInterfaces(logger *log.Logger, interfaces []net.Interface) (filtered []net.Interface, err error) { - var conn *rtnetlink.Conn - - for _, iface := range interfaces { - switch { - case strings.HasPrefix(iface.Name, "en"): - filtered = append(filtered, iface) - case strings.HasPrefix(iface.Name, "eth"): - filtered = append(filtered, iface) - case strings.HasPrefix(iface.Name, "lo"): - filtered = append(filtered, iface) - case strings.HasPrefix(iface.Name, "bond"): - filtered = append(filtered, iface) - } - } - - conn, err = rtnetlink.Dial(nil) - if err != nil { - return nil, err - } - - //nolint:errcheck - defer conn.Close() - - n := 0 //nolint:wsl - for _, iface := range filtered { - link, err := conn.Link.Get(uint32(iface.Index)) - if err != nil { - logger.Printf("error getting link %q", iface.Name) - - continue - } - - if link.Flags&unix.IFF_UP == unix.IFF_UP && !(link.Flags&unix.IFF_RUNNING == unix.IFF_RUNNING) { - logger.Printf("no carrier for link %q", iface.Name) - } else { - logger.Printf("link %q has carrier signal", iface.Name) - filtered[n] = iface - n++ - } - } - - filtered = filtered[:n] - - return filtered, nil -} - -// writeResolvConf generates a /etc/resolv.conf with the specified nameservers. -func writeResolvConf(logger *log.Logger, resolvers []string) (err error) { - var resolvconf strings.Builder - - for idx, resolver := range resolvers { - // Only allow the first 3 nameservers since that is all that will be used - if idx >= 3 { - break - } - - if _, err = resolvconf.WriteString(fmt.Sprintf("nameserver %s\n", resolver)); err != nil { - logger.Println("failed to add some resolver to resolvconf:", resolver) - - return err - } - } - - if domain, err := talosnet.DomainName(); err == nil { - if domain != "" { - if _, err = resolvconf.WriteString(fmt.Sprintf("search %s\n", domain)); err != nil { - return fmt.Errorf("failed to add domain search line to resolvconf: %s", err) - } - } - } - - logger.Println("writing resolvconf") - - return ioutil.WriteFile("/etc/resolv.conf", []byte(resolvconf.String()), 0o644) -} - -const hostsTemplate = ` -127.0.0.1 localhost -{{ .IP }} {{ .Hostname }} {{ if ne .Hostname .Alias }}{{ .Alias }}{{ end }} -::1 localhost ip6-localhost ip6-loopback -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters - -{{ with .ExtraHosts }} -{{ range . }} -{{ .IP }} {{ range .Aliases }}{{.}} {{ end }} -{{ end }} -{{ end }} -` - -func writeHosts(hostname string, address net.IP, cfg config.Provider) (err error) { - extraHosts := []config.ExtraHost{} - - if cfg != nil { - extraHosts = cfg.Machine().Network().ExtraHosts() - } - - data := struct { - IP string - Hostname string - Alias string - ExtraHosts []config.ExtraHost - }{ - IP: address.String(), - Hostname: hostname, - Alias: strings.Split(hostname, ".")[0], - ExtraHosts: extraHosts, - } - - var tmpl *template.Template - - tmpl, err = template.New("").Parse(hostsTemplate) - if err != nil { - return err - } - - var buf []byte - - writer := bytes.NewBuffer(buf) - - err = tmpl.Execute(writer, data) - if err != nil { - return err - } - - return ioutil.WriteFile("/etc/hosts", writer.Bytes(), 0o644) -} diff --git a/internal/app/networkd/pkg/networkd/netconf.go b/internal/app/networkd/pkg/networkd/netconf.go deleted file mode 100644 index 7acac610d..000000000 --- a/internal/app/networkd/pkg/networkd/netconf.go +++ /dev/null @@ -1,323 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package networkd - -import ( - "fmt" - "log" - "net" - "strings" - - "github.com/talos-systems/go-procfs/procfs" - - "github.com/talos-systems/talos/internal/app/networkd/pkg/address" - "github.com/talos-systems/talos/internal/app/networkd/pkg/nic" - "github.com/talos-systems/talos/pkg/machinery/config" - "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -// buildOptions translates the supplied config to nic.Option used for -// configuring the interface. -//nolint:gocyclo,cyclop -func buildOptions(logger *log.Logger, device config.Device, hostname string) (name string, opts []nic.Option, err error) { - opts = append(opts, nic.WithName(device.Interface())) - - if device.Ignore() || procfs.ProcCmdline().Get(constants.KernelParamNetworkInterfaceIgnore).Contains(device.Interface()) { - opts = append(opts, nic.WithIgnore()) - - return device.Interface(), opts, err - } - - // Configure Addressing - switch { - case device.CIDR() != "": - s := &address.Static{CIDR: device.CIDR(), RouteList: device.Routes(), Mtu: device.MTU()} - - // Set a default for the hostname to ensure we always have a valid - // ip + hostname pair - ip := s.Address().IP.String() - s.FQDN = fmt.Sprintf("%s-%s", "talos", strings.ReplaceAll(ip, ".", "-")) - - if hostname != "" { - s.FQDN = hostname - } - - opts = append(opts, nic.WithAddressing(s)) - case device.DHCP(): - if device.DHCPOptions().IPv4() { - d := &address.DHCP4{DHCPOptions: device.DHCPOptions(), RouteList: device.Routes(), Mtu: device.MTU()} - opts = append(opts, nic.WithAddressing(d)) - } - - if device.DHCPOptions().IPv6() { - d := &address.DHCP6{Mtu: device.MTU()} - opts = append(opts, nic.WithAddressing(d)) - } - default: - // Allow master interface without any addressing if VLANs exist - if len(device.Vlans()) > 0 { - logger.Printf("no addressing for master device %s", device.Interface()) - - opts = append(opts, nic.WithNoAddressing()) - } else { - // No CIDR and DHCP==false results in a static without an IP. - // This handles cases like slaac addressing. - s := &address.Static{RouteList: device.Routes(), Mtu: device.MTU()} - opts = append(opts, nic.WithAddressing(s)) - } - } - - // Configure Vlan interfaces - for _, vlan := range device.Vlans() { - opts = append(opts, nic.WithVlan(vlan.ID())) - if vlan.CIDR() != "" { - opts = append(opts, nic.WithVlanCIDR(vlan.ID(), vlan.CIDR(), vlan.Routes())) - } - - if vlan.DHCP() { - opts = append(opts, nic.WithVlanDhcp(vlan.ID())) - } - } - - // Handle dummy interface - if device.Dummy() { - opts = append(opts, nic.WithDummy()) - } - - if device.WireguardConfig() != nil { - opts = append(opts, nic.WithWireguardConfig(device.WireguardConfig())) - } - - if device.VIPConfig() != nil { - opts = append(opts, nic.WithVIPConfig(device.VIPConfig())) - } - - // Configure Bonding - if device.Bond() == nil { - return device.Interface(), opts, err - } - - opts = append(opts, nic.WithBond(true)) - - if len(device.Bond().Interfaces()) == 0 { - return device.Interface(), opts, fmt.Errorf("invalid bond configuration for %s: must supply sub interfaces for bonded interface", device.Interface()) - } - - opts = append(opts, nic.WithSubInterface(device.Bond().Interfaces()...)) - - if device.Bond().Mode() != "" { - opts = append(opts, nic.WithBondMode(device.Bond().Mode())) - } - - if device.Bond().HashPolicy() != "" { - opts = append(opts, nic.WithHashPolicy(device.Bond().HashPolicy())) - } - - if device.Bond().LACPRate() != "" { - opts = append(opts, nic.WithLACPRate(device.Bond().LACPRate())) - } - - if device.Bond().MIIMon() > 0 { - opts = append(opts, nic.WithMIIMon(device.Bond().MIIMon())) - } - - if device.Bond().UpDelay() > 0 { - opts = append(opts, nic.WithUpDelay(device.Bond().UpDelay())) - } - - if device.Bond().DownDelay() > 0 { - opts = append(opts, nic.WithDownDelay(device.Bond().DownDelay())) - } - - if !device.Bond().UseCarrier() { - opts = append(opts, nic.WithUseCarrier(device.Bond().UseCarrier())) - } - - if device.Bond().ARPInterval() > 0 { - opts = append(opts, nic.WithARPInterval(device.Bond().ARPInterval())) - } - - // if device.Bond.ARPIPTarget { - // opts = append(opts, nic.WithARPIPTarget(device.Bond.ARPIPTarget)) - //} - - if device.Bond().ARPValidate() != "" { - opts = append(opts, nic.WithARPValidate(device.Bond().ARPValidate())) - } - - if device.Bond().ARPAllTargets() != "" { - opts = append(opts, nic.WithARPAllTargets(device.Bond().ARPAllTargets())) - } - - if device.Bond().Primary() != "" { - opts = append(opts, nic.WithPrimary(device.Bond().Primary())) - } - - if device.Bond().PrimaryReselect() != "" { - opts = append(opts, nic.WithPrimaryReselect(device.Bond().PrimaryReselect())) - } - - if device.Bond().FailOverMac() != "" { - opts = append(opts, nic.WithFailOverMAC(device.Bond().FailOverMac())) - } - - if device.Bond().ResendIGMP() > 0 { - opts = append(opts, nic.WithResendIGMP(device.Bond().ResendIGMP())) - } - - if device.Bond().NumPeerNotif() > 0 { - opts = append(opts, nic.WithNumPeerNotif(device.Bond().NumPeerNotif())) - } - - if device.Bond().AllSlavesActive() > 0 { - opts = append(opts, nic.WithAllSlavesActive(device.Bond().AllSlavesActive())) - } - - if device.Bond().MinLinks() > 0 { - opts = append(opts, nic.WithMinLinks(device.Bond().MinLinks())) - } - - if device.Bond().LPInterval() > 0 { - opts = append(opts, nic.WithLPInterval(device.Bond().LPInterval())) - } - - if device.Bond().PacketsPerSlave() > 0 { - opts = append(opts, nic.WithPacketsPerSlave(device.Bond().PacketsPerSlave())) - } - - if device.Bond().ADSelect() != "" { - opts = append(opts, nic.WithADSelect(device.Bond().ADSelect())) - } - - if device.Bond().ADActorSysPrio() > 0 { - opts = append(opts, nic.WithADActorSysPrio(device.Bond().ADActorSysPrio())) - } - - if device.Bond().ADUserPortKey() > 0 { - opts = append(opts, nic.WithADUserPortKey(device.Bond().ADUserPortKey())) - } - - // if device.Bond.ADActorSystem != "" { - // opts = append(opts, nic.WithADActorSystem(device.Bond.ADActorSystem)) - //} - - if device.Bond().TLBDynamicLB() > 0 { - opts = append(opts, nic.WithTLBDynamicLB(device.Bond().TLBDynamicLB())) - } - - if device.Bond().PeerNotifyDelay() > 0 { - opts = append(opts, nic.WithPeerNotifyDelay(device.Bond().PeerNotifyDelay())) - } - - return device.Interface(), opts, err -} - -//nolint:gocyclo -func buildKernelOptions(cmdline string) (name string, opts []nic.Option) { - // https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt - // ip=::::::::: - fields := strings.Split(cmdline, ":") - - // If dhcp is specified, we'll handle it as a normal discovered - // interface - if len(fields) == 1 && fields[0] == "dhcp" { - return name, opts - } - - // If there are not enough fields specified, we'll bail - if len(fields) < 4 { - return name, opts - } - - var ( - device = &v1alpha1.Device{} - hostname string - link *net.Interface - resolvers = []net.IP{} - ) - - for idx, field := range fields { - switch idx { - // Address - case 0: - device.DeviceCIDR = field - // NFS Server - // case 1: - // Gateway - case 2: - device.DeviceRoutes = []*v1alpha1.Route{ - { - RouteNetwork: "0.0.0.0/0", - RouteGateway: field, - }, - } - // Netmask - case 3: - mask := net.ParseIP(field).To4() - ipmask := net.IPv4Mask(mask[0], mask[1], mask[2], mask[3]) - ones, _ := ipmask.Size() - device.DeviceCIDR = fmt.Sprintf("%s/%d", device.CIDR(), ones) - // Hostname - case 4: - hostname = field - // Interface name - case 5: - iface, err := net.InterfaceByName(field) - if err == nil { - link = iface - } - // Configuration method - // case 6: - // Primary DNS Resolver - case 7: - fallthrough - // Secondary DNS Resolver - case 8: - nameserverIP := net.ParseIP(field) - if nameserverIP != nil { - resolvers = append(resolvers, nameserverIP) - } - } - } - // NTP server - // case 9: - // // k.NTPServer = field - - // Find the first non-loopback interface - if link == nil { - ifaces, err := net.Interfaces() - if err != nil { - return hostname, opts - } - - for _, iface := range ifaces { - if iface.Flags&net.FlagLoopback != 0 { - continue - } - - i := iface - - link = &i - - break - } - } - - if device.DeviceInterface == "" { - opts = append(opts, nic.WithName(link.Name)) - } - - routes := make([]config.Route, len(device.DeviceRoutes)) - - for i := 0; i < len(device.DeviceRoutes); i++ { - routes[i] = device.DeviceRoutes[i] - } - - s := &address.Static{Mtu: device.DeviceMTU, NameServers: resolvers, FQDN: hostname, NetIf: link, CIDR: device.DeviceCIDR, RouteList: routes} - opts = append(opts, nic.WithAddressing(s)) - - return link.Name, opts -} diff --git a/internal/app/networkd/pkg/networkd/netconf_test.go b/internal/app/networkd/pkg/networkd/netconf_test.go deleted file mode 100644 index 0687cd967..000000000 --- a/internal/app/networkd/pkg/networkd/netconf_test.go +++ /dev/null @@ -1,147 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -//nolint:testpackage -package networkd - -import ( - "log" - "net" - "os" - "testing" - - "github.com/stretchr/testify/suite" - - "github.com/talos-systems/talos/internal/app/networkd/pkg/nic" - "github.com/talos-systems/talos/pkg/machinery/config" - "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1" -) - -type NetconfSuite struct { - suite.Suite -} - -func TestNetconfSuite(t *testing.T) { - // Hide all our state transition messages - // log.SetOutput(ioutil.Discard) - suite.Run(t, new(NetconfSuite)) -} - -func (suite *NetconfSuite) TestBaseNetconf() { - for _, device := range sampleConfig() { - _, opts, err := buildOptions(log.New(os.Stderr, "", log.LstdFlags), device, "") - suite.Require().NoError(err) - - _, err = nic.New(opts...) - suite.Require().NoError(err) - } -} - -func (suite *NetconfSuite) TestKernelNetconf() { - name, opts := buildKernelOptions(sampleKernelIPParam()) - - iface, err := nic.New(opts...) - suite.Require().NoError(err) - - suite.Assert().Equal(iface.Name, name) - suite.Assert().Equal(len(iface.AddressMethod), 1) - addr := iface.AddressMethod[0] - suite.Assert().Equal(addr.Name(), "static") - suite.Assert().Equal(addr.Hostname(), "hostname") - suite.Assert().Equal(addr.Address().IP, net.ParseIP("1.1.1.1")) - suite.Assert().Equal(len(addr.Resolvers()), 2) - suite.Assert().Equal(addr.Resolvers()[0], net.ParseIP("4.4.4.4")) - suite.Assert().Equal(addr.Resolvers()[1], net.ParseIP("5.5.5.5")) - suite.Assert().Equal(len(addr.Routes()), 1) -} - -func (suite *NetconfSuite) TestKernelNetconfIncomplete() { - name, opts := buildKernelOptions("1.1.1.1::3.3.3.3:255.255.255.0::eth0:none:::") - - iface, err := nic.New(opts...) - suite.Require().NoError(err) - - suite.Assert().Equal(iface.Name, name) - suite.Assert().Equal(len(iface.AddressMethod), 1) - addr := iface.AddressMethod[0] - suite.Assert().Equal(addr.Name(), "static") - suite.Assert().Equal(addr.Hostname(), "") - suite.Assert().Equal(addr.Address().IP, net.ParseIP("1.1.1.1")) - suite.Assert().Len(addr.Resolvers(), 0) - suite.Assert().Equal(len(addr.Routes()), 1) -} - -func sampleConfig() []config.Device { - return []config.Device{ - &v1alpha1.Device{ - DeviceInterface: "eth0", - DeviceCIDR: "192.168.0.10/24", - }, - &v1alpha1.Device{ - DeviceInterface: "bond0", - DeviceCIDR: "192.168.0.10/24", - DeviceBond: &v1alpha1.Bond{BondInterfaces: []string{"lo"}}, - }, - &v1alpha1.Device{ - DeviceInterface: "bond0", - DeviceBond: &v1alpha1.Bond{BondInterfaces: []string{"lo"}, BondMode: "balance-rr"}, - }, - &v1alpha1.Device{ - DeviceInterface: "eth0", - DeviceIgnore: true, - }, - &v1alpha1.Device{ - DeviceInterface: "eth0", - DeviceMTU: 9100, - DeviceCIDR: "192.168.0.10/24", - DeviceRoutes: []*v1alpha1.Route{{RouteNetwork: "10.0.0.0/8", RouteGateway: "10.0.0.1"}}, - }, - &v1alpha1.Device{ - DeviceInterface: "bond0", - DeviceBond: &v1alpha1.Bond{ - BondInterfaces: []string{"lo"}, - BondMode: "balance-rr", - BondHashPolicy: "layer2", - BondLACPRate: "fast", - BondMIIMon: 200, - BondUpDelay: 100, - BondDownDelay: 100, - }, - }, - &v1alpha1.Device{ - DeviceInterface: "bondyolo0", - DeviceBond: &v1alpha1.Bond{ - BondInterfaces: []string{"lo"}, - BondMode: "balance-rr", - BondHashPolicy: "layer2", - BondLACPRate: "fast", - BondMIIMon: 200, - BondUpDelay: 100, - BondDownDelay: 100, - BondUseCarrier: nil, - BondARPInterval: 230, - BondARPValidate: "all", - BondARPAllTargets: "all", - BondPrimary: "lo", - BondPrimaryReselect: "better", - BondFailOverMac: "none", - BondResendIGMP: 10, - BondNumPeerNotif: 5, - BondAllSlavesActive: 1, - BondMinLinks: 1, - BondLPInterval: 100, - BondPacketsPerSlave: 50, - BondADSelect: "bandwidth", - BondADActorSysPrio: 23, - BondADUserPortKey: 323, - BondTLBDynamicLB: 1, - BondPeerNotifyDelay: 200, - }, - }, - } -} - -func sampleKernelIPParam() string { - return "1.1.1.1:2.2.2.2:3.3.3.3:255.255.255.0:hostname:eth0:none:4.4.4.4:5.5.5.5:6.6.6.6" -} diff --git a/internal/app/networkd/pkg/networkd/networkd.go b/internal/app/networkd/pkg/networkd/networkd.go deleted file mode 100644 index ab9aef4ba..000000000 --- a/internal/app/networkd/pkg/networkd/networkd.go +++ /dev/null @@ -1,468 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// Package networkd handles the network interface configuration on a host. -// If no configuration is provided, automatic configuration via dhcp will -// be performed on interfaces ( eth, en, bond ). -package networkd - -import ( - "context" - "fmt" - "log" - "net" - "sort" - "strings" - "sync" - "time" - - multierror "github.com/hashicorp/go-multierror" - "github.com/talos-systems/go-procfs/procfs" - "golang.org/x/sync/errgroup" - "golang.org/x/sys/unix" - - "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" - "github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform" - "github.com/talos-systems/talos/internal/app/networkd/pkg/address" - "github.com/talos-systems/talos/internal/app/networkd/pkg/nic" - "github.com/talos-systems/talos/pkg/machinery/config" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -// Set up default nameservers. -const ( - DefaultPrimaryResolver = "1.1.1.1" - DefaultSecondaryResolver = "8.8.8.8" -) - -// Networkd provides the high level interaction to configure network interfaces -// on a host system. This currently supports addressing configuration via dhcp -// and/or a specified configuration file. -type Networkd struct { - Interfaces map[string]*nic.NetworkInterface - Config config.Provider - - hostname string - resolvers []string - - sync.Mutex - ready bool - - logger *log.Logger -} - -// New takes the supplied configuration and creates an abstract representation -// of all interfaces (as nic.NetworkInterface). -//nolint:gocyclo,cyclop -func New(logger *log.Logger, config config.Provider) (*Networkd, error) { - var ( - hostname string - option *string - result *multierror.Error - resolvers []string - ) - - netconf := make(map[string][]nic.Option) - - if option = procfs.ProcCmdline().Get("ip").First(); option != nil { - if name, opts := buildKernelOptions(*option); name != "" { - netconf[name] = opts - } - } - - // Gather settings for all config driven interfaces - if config != nil { - logger.Println("parsing configuration file") - - for _, device := range config.Machine().Network().Devices() { - name, opts, err := buildOptions(logger, device, config.Machine().Network().Hostname()) - if err != nil { - result = multierror.Append(result, err) - - continue - } - - if _, ok := netconf[name]; ok { - netconf[name] = append(netconf[name], opts...) - } else { - netconf[name] = opts - } - } - - hostname = config.Machine().Network().Hostname() - - if len(config.Machine().Network().Resolvers()) > 0 { - resolvers = config.Machine().Network().Resolvers() - } - } - - logger.Println("discovering local interfaces") - - // Gather already present interfaces - localInterfaces, err := net.Interfaces() - if err != nil { - result = multierror.Append(result, err) - - return &Networkd{}, result.ErrorOrNil() - } - - // Add locally discovered interfaces to our list of interfaces - // if they are not already present - filtered, err := filterInterfaces(logger, localInterfaces) - if err != nil { - result = multierror.Append(result, err) - - return &Networkd{}, result.ErrorOrNil() - } - - for _, device := range filtered { - if _, ok := netconf[device.Name]; !ok { - netconf[device.Name] = []nic.Option{nic.WithName(device.Name)} - - // Explicitly ignore bonded interfaces if no configuration was specified - // This should speed up initial boot times since an unconfigured bond - // does not provide any value. - if strings.HasPrefix(device.Name, "bond") { - netconf[device.Name] = append(netconf[device.Name], nic.WithIgnore()) - } - } - - // Ensure lo has proper loopback address - // Ensure MTU for loopback is 64k - // ref: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0cf833aefaa85bbfce3ff70485e5534e09254773 - if strings.HasPrefix(device.Name, "lo") { - netconf[device.Name] = append(netconf[device.Name], nic.WithAddressing( - &address.Static{ - CIDR: "127.0.0.1/8", - Mtu: nic.MaximumMTU, - }, - )) - } - } - - // add local interfaces which were filtered out with Ignore - for _, device := range localInterfaces { - if _, ok := netconf[device.Name]; !ok { - netconf[device.Name] = []nic.Option{nic.WithName(device.Name), nic.WithIgnore()} - } - } - - interfaces := make(map[string]*nic.NetworkInterface) - - // Create nic.NetworkInterface representation of the interface - for ifname, opts := range netconf { - netif, err := nic.New(opts...) - if err != nil { - result = multierror.Append(result, err) - - continue - } - - interfaces[ifname] = netif - } - - // Set interfaces that are part of a bond to ignored - for _, netif := range interfaces { - if !netif.Bonded { - continue - } - - for _, subif := range netif.SubInterfaces { - if _, ok := interfaces[subif.Name]; !ok { - result = multierror.Append(result, fmt.Errorf("bond subinterface %s does not exist", subif.Name)) - - continue - } - - interfaces[subif.Name].Ignore = true - } - } - - return &Networkd{ - Interfaces: interfaces, - Config: config, - hostname: hostname, - resolvers: resolvers, - logger: logger, - }, result.ErrorOrNil() -} - -// Configure handles the lifecycle for an interface. This includes creation, -// configuration, and any addressing that is needed. We care about ordering -// here so that we can ensure any links that make up a bond will be in -// the correct state when we get to bonding configuration. -// -//nolint:gocyclo -func (n *Networkd) Configure(ctx context.Context) (err error) { - // Configure non-bonded interfaces first so we can ensure basic - // interfaces exist prior to bonding - for _, bonded := range []bool{false, true} { - if bonded { - n.logger.Println("configuring bonded interfaces") - } else { - n.logger.Println("configuring non-bonded interfaces") - } - - if err = n.configureLinks(ctx, bonded); err != nil { - // Treat errors as non-fatal - n.logger.Println(err) - } - } - - // prefer resolvers from the configuration - resolvers := append([]string(nil), n.resolvers...) - - // if no resolvers configured, use addressing method resolvers - if len(resolvers) == 0 { - for _, netif := range n.Interfaces { - for _, method := range netif.AddressMethod { - if !method.Valid() { - continue - } - - for _, resolver := range method.Resolvers() { - resolvers = append(resolvers, resolver.String()) - } - } - } - } - - // use default resolvers if nothing is configured - if len(resolvers) == 0 { - resolvers = append(resolvers, DefaultPrimaryResolver, DefaultSecondaryResolver) - } - - // Set hostname must be before the resolv configuration - // so we can ensure the hosts domainname is set properly - // before we write the search stanza - if err = n.Hostname(); err != nil { - return err - } - - if err = writeResolvConf(n.logger, resolvers); err != nil { - return err - } - - n.SetReady() - - return nil -} - -// Renew sets up a long running loop to refresh a network interfaces -// addressing configuration. Currently this only applies to interfaces -// configured by DHCP. -func (n *Networkd) Renew(ctx context.Context) { - for _, iface := range n.Interfaces { - iface.Renew(ctx, n.logger) - } -} - -// Reset handles removing addresses from previously configured interfaces. -func (n *Networkd) Reset() { - for _, iface := range n.Interfaces { - iface.Reset() - } -} - -// RunControllers spins up additional controllers in the errgroup. -func (n *Networkd) RunControllers(ctx context.Context, eg *errgroup.Group) error { - for _, iface := range n.Interfaces { - if err := iface.RunControllers(ctx, n.logger, eg); err != nil { - return err - } - } - - return nil -} - -// Hostname returns the first hostname found from the addressing methods. -// Create /etc/hosts and set hostname. -// Priority is: -// 1. Config (explicitly defined by the user) -// 2. Kernel arg -// 3. Platform -// 4. DHCP -// 5. Default with the format: talos-. -func (n *Networkd) Hostname() (err error) { - hostname, domainname, address, err := n.decideHostname() - if err != nil { - return err - } - - if err = writeHosts(hostname, address, n.Config); err != nil { - return err - } - - var p runtime.Platform - - p, err = platform.CurrentPlatform() - if err != nil { - return err - } - - // Skip hostname/domainname setting when running in container mode - if p.Mode() == runtime.ModeContainer { - return nil - } - - if err = unix.Sethostname([]byte(hostname)); err != nil { - return err - } - - return unix.Setdomainname([]byte(domainname)) -} - -//nolint:gocyclo -func (n *Networkd) decideHostname() (hostname, domainname string, address net.IP, err error) { - // Set hostname to default - address = net.ParseIP("127.0.1.1") - hostname = fmt.Sprintf("%s-%s", "talos", strings.ReplaceAll(address.String(), ".", "-")) - - // Sort interface names alphabetically so we can ensure parsing order - interfaceNames := make([]string, 0, len(n.Interfaces)) - for intName := range n.Interfaces { - interfaceNames = append(interfaceNames, intName) - } - - sort.Strings(interfaceNames) - - // Loop through address responses and use the first hostname - // and address response. -outer: - for _, intName := range interfaceNames { - iface := n.Interfaces[intName] - - // Skip loopback interface because it will always have - // a hardcoded hostname of `talos-ip` - if iface.Link != nil && iface.Link.Flags&net.FlagLoopback != 0 { - continue - } - - for _, method := range iface.AddressMethod { - if !method.Valid() { - continue - } - - if method.Hostname() != "" { - hostname = method.Hostname() - - address = method.Address().IP - - break outer - } - } - } - - // Platform - var p runtime.Platform - - ctx, ctxCancel := context.WithTimeout(context.Background(), 30*time.Second) - defer ctxCancel() - - p, err = platform.CurrentPlatform() - if err == nil { - var pHostname []byte - - if pHostname, err = p.Hostname(ctx); err == nil && string(pHostname) != "" { - hostname = string(pHostname) - } - } - - // Kernel - if kernelHostname := procfs.ProcCmdline().Get(constants.KernelParamHostname).First(); kernelHostname != nil { - hostname = *kernelHostname - } - - // Allow user supplied hostname to win - if n.hostname != "" { - hostname = n.hostname - } - - hostParts := strings.Split(hostname, ".") - - if len(hostParts[0]) > 63 { - return "", "", net.IP{}, fmt.Errorf("hostname length longer than max allowed (63): %s", hostParts[0]) - } - - if len(hostname) > 253 { - return "", "", net.IP{}, fmt.Errorf("hostname fqdn length longer than max allowed (253): %s", hostname) - } - - hostname = hostParts[0] - - if len(hostParts) > 1 { - domainname = strings.Join(hostParts[1:], ".") - } - - // Only return the hostname portion of the name ( strip domain bits off ) - return hostname, domainname, address, nil -} - -// Ready exposes the readiness state of networkd. -func (n *Networkd) Ready() bool { - n.Lock() - defer n.Unlock() - - return n.ready -} - -// SetReady sets the readiness state of networkd. -func (n *Networkd) SetReady() { - n.Lock() - defer n.Unlock() - - n.ready = true -} - -func (n *Networkd) configureLinks(ctx context.Context, bonded bool) error { - errCh := make(chan error, len(n.Interfaces)) - count := 0 - - for _, iface := range n.Interfaces { - if iface.Bonded != bonded { - continue - } - - count++ - - go func(netif *nic.NetworkInterface) { - if !netif.IsIgnored() { - n.logger.Printf("setting up %s", netif.Name) - } - - errCh <- func() error { - // Ensure link exists - if err := netif.Create(); err != nil { - return fmt.Errorf("error creating nic %q: %w", netif.Name, err) - } - - if err := netif.CreateSub(n.logger); err != nil { - return fmt.Errorf("error creating sub interface nic %q: %w", netif.Name, err) - } - - if err := netif.Configure(ctx); err != nil { - return fmt.Errorf("error configuring nic %q: %w", netif.Name, err) - } - - if err := netif.Addressing(n.logger); err != nil { - return fmt.Errorf("error configuring addressing %q: %w", netif.Name, err) - } - - if err := netif.AddressingSub(n.logger); err != nil { - return fmt.Errorf("error configuring addressing %q: %w", netif.Name, err) - } - - return nil - }() - }(iface) - } - - var multiErr *multierror.Error - - for i := 0; i < count; i++ { - multiErr = multierror.Append(multiErr, <-errCh) - } - - return multiErr.ErrorOrNil() -} diff --git a/internal/app/networkd/pkg/networkd/networkd_test.go b/internal/app/networkd/pkg/networkd/networkd_test.go deleted file mode 100644 index 84142ee9f..000000000 --- a/internal/app/networkd/pkg/networkd/networkd_test.go +++ /dev/null @@ -1,213 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -//nolint:testpackage -package networkd - -import ( - "log" - "net" - "os" - "testing" - - "github.com/insomniacslk/dhcp/dhcpv4" - "github.com/stretchr/testify/suite" - - "github.com/talos-systems/talos/internal/app/networkd/pkg/address" - "github.com/talos-systems/talos/pkg/machinery/config" - "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1" -) - -type NetworkdSuite struct { - suite.Suite -} - -func TestNetworkdSuite(t *testing.T) { - // Hide all our state transition messages - // log.SetOutput(ioutil.Discard) - suite.Run(t, new(NetworkdSuite)) -} - -func (suite *NetworkdSuite) TestNetworkd() { - nwd, err := New(log.New(os.Stderr, "", log.LstdFlags), sampleConfigFile()) - suite.Require().NoError(err) - - suite.Require().Contains(nwd.Interfaces, "eth0") - suite.Assert().False(nwd.Interfaces["eth0"].Bonded) - suite.Require().Contains(nwd.Interfaces, "bond0") - suite.Assert().True(nwd.Interfaces["bond0"].Bonded) - suite.Assert().Equal(1, len(nwd.Interfaces["bond0"].SubInterfaces)) - suite.Require().Contains(nwd.Interfaces, "lo") -} - -func (suite *NetworkdSuite) TestHostname() { - var ( - addr net.IP - domainname string - err error - hostname string - nwd *Networkd - sampleConfig config.Provider - ) - - nwd, err = New(log.New(os.Stderr, "", log.LstdFlags), nil) - suite.Require().NoError(err) - - // Default test - hostname, _, addr, err = nwd.decideHostname() - suite.Require().NoError(err) - suite.Assert().Equal("talos-127-0-1-1", hostname) - suite.Assert().Equal(addr, net.ParseIP("127.0.1.1")) - - // Static addressing tests - - // Static with hostname - sampleConfig = sampleConfigFile() - - nwd, err = New(log.New(os.Stderr, "", log.LstdFlags), sampleConfig) - suite.Require().NoError(err) - - hostname, _, addr, err = nwd.decideHostname() - suite.Require().NoError(err) - suite.Assert().Equal("myhostname", hostname) - suite.Assert().Equal(addr, net.ParseIP("192.168.0.10")) - - // Static for computed hostname ( talos-ip ) - sampleConfig.(*v1alpha1.Config).MachineConfig.MachineNetwork.NetworkHostname = "" - - nwd, err = New(log.New(os.Stderr, "", log.LstdFlags), sampleConfig) - suite.Require().NoError(err) - - hostname, _, addr, err = nwd.decideHostname() - suite.Require().NoError(err) - suite.Assert().Equal("talos-192-168-0-10", hostname) - suite.Assert().Equal(addr, net.ParseIP("192.168.0.10")) - - // Static for hostname too long - sampleConfig.(*v1alpha1.Config).MachineConfig.MachineNetwork.NetworkHostname = "somereallyreallyreallylongstringthathasmorethan63charactersbecauseweneedtotestit" - - nwd, err = New(log.New(os.Stderr, "", log.LstdFlags), sampleConfig) - suite.Require().NoError(err) - - //nolint:dogsled - _, _, _, err = nwd.decideHostname() - suite.Require().Error(err) - - // Static for hostname vs domain name - sampleConfig.(*v1alpha1.Config).MachineConfig.MachineNetwork.NetworkHostname = "dadjokes.biz.dev.com.org.io" - - nwd, err = New(log.New(os.Stderr, "", log.LstdFlags), sampleConfig) - suite.Require().NoError(err) - - hostname, domainname, _, err = nwd.decideHostname() - suite.Require().NoError(err) - suite.Assert().Equal("dadjokes", hostname) - suite.Assert().Equal("biz.dev.com.org.io", domainname) - - // DHCP addressing tests - - // DHCP with OptionHostName - nwd, err = New(log.New(os.Stderr, "", log.LstdFlags), dhcpConfigFile()) - suite.Require().NoError(err) - - nwd.Interfaces["eth0"].AddressMethod = []address.Addressing{ - &address.DHCP4{ - Ack: &dhcpv4.DHCPv4{ - YourIPAddr: net.ParseIP("192.168.0.11"), - Options: dhcpv4.Options{ - uint8(dhcpv4.OptionHostName): []byte("evenbetterdadjokes"), - uint8(dhcpv4.OptionSubnetMask): []byte{255, 255, 255, 0}, - }, - }, - }, - } - - hostname, _, addr, err = nwd.decideHostname() - suite.Require().NoError(err) - suite.Assert().Equal("evenbetterdadjokes", hostname) - suite.Assert().Equal(addr.String(), "192.168.0.11") - - // DHCP without OptionHostName - nwd, err = New(log.New(os.Stderr, "", log.LstdFlags), dhcpConfigFile()) - suite.Require().NoError(err) - - nwd.Interfaces["eth0"].AddressMethod = []address.Addressing{ - &address.DHCP4{ - Ack: &dhcpv4.DHCPv4{ - YourIPAddr: net.ParseIP("192.168.0.11"), - Options: dhcpv4.Options{ - uint8(dhcpv4.OptionSubnetMask): []byte{255, 255, 255, 0}, - }, - }, - }, - } - - hostname, _, addr, err = nwd.decideHostname() - suite.Require().NoError(err) - suite.Assert().Equal("talos-192-168-0-11", hostname) - suite.Assert().Equal(addr, net.ParseIP("192.168.0.11")) - - // DHCP without OptionHostname and with OptionDomainName - nwd.Interfaces["eth0"].AddressMethod = []address.Addressing{ - &address.DHCP4{ - Ack: &dhcpv4.DHCPv4{ - YourIPAddr: net.ParseIP("192.168.0.11"), - Options: dhcpv4.Options{ - uint8(dhcpv4.OptionDomainName): []byte("domain.tld"), - }, - }, - }, - } - - hostname, domainname, addr, err = nwd.decideHostname() - suite.Require().NoError(err) - suite.Assert().Equal("talos-192-168-0-11", hostname) - suite.Assert().Equal("domain.tld", domainname) - suite.Assert().Equal(addr, net.ParseIP("192.168.0.11")) -} - -func sampleConfigFile() config.Provider { - return &v1alpha1.Config{ - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NameServers: []string{"1.2.3.4", "2.3.4.5"}, - NetworkHostname: "myhostname", - NetworkInterfaces: []*v1alpha1.Device{ - { - DeviceInterface: "eth0", - DeviceCIDR: "192.168.0.10/24", - DeviceMTU: 9100, - }, - { - DeviceInterface: "bond0", - DeviceCIDR: "192.168.0.10/24", - DeviceBond: &v1alpha1.Bond{ - BondInterfaces: []string{"lo"}, - BondMode: "balance-rr", - }, - }, - }, - }, - }, - } -} - -func dhcpConfigFile() config.Provider { - return &v1alpha1.Config{ - MachineConfig: &v1alpha1.MachineConfig{ - MachineNetwork: &v1alpha1.NetworkConfig{ - NetworkInterfaces: []*v1alpha1.Device{ - { - DeviceInterface: "eth0", - }, - { - DeviceInterface: "eth1", - DeviceCIDR: "192.168.0.10/24", - DeviceMTU: 9100, - }, - }, - }, - }, - } -} diff --git a/internal/app/networkd/pkg/nic/bond_options.go b/internal/app/networkd/pkg/nic/bond_options.go deleted file mode 100644 index 0654acba0..000000000 --- a/internal/app/networkd/pkg/nic/bond_options.go +++ /dev/null @@ -1,373 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// Additional information can be found -// https://www.kernel.org/doc/Documentation/networking/bonding.txt. - -package nic - -import ( - "net" -) - -// WithBond defines if the interface should be bonded. -func WithBond(o bool) Option { - return func(n *NetworkInterface) (err error) { - n.Bonded = o - - return nil - } -} - -// WithSubInterface defines which interfaces make up the bond. -func WithSubInterface(o ...string) Option { - return func(n *NetworkInterface) (err error) { - var found bool - - for _, ifname := range o { - found = false - - for _, subif := range n.SubInterfaces { - if ifname == subif.Name { - found = true - - break - } - } - - if found { - continue - } - - var iface *net.Interface - - iface, err = net.InterfaceByName(ifname) - if err != nil { - return err - } - - n.SubInterfaces = append(n.SubInterfaces, iface) - } - - return err - } -} - -// WithBondMode sets the mode the bond should operate in. -func WithBondMode(o string) Option { - return func(n *NetworkInterface) (err error) { - var mode BondMode - - if mode, err = BondModeByName(o); err != nil { - return err - } - - n.BondSettings.Uint8(uint16(IFLA_BOND_MODE), uint8(mode)) - - return err - } -} - -// WithHashPolicy configures the transmit hash policy for the bonded interface. -func WithHashPolicy(o string) Option { - return func(n *NetworkInterface) (err error) { - var policy BondXmitHashPolicy - - if policy, err = BondXmitHashPolicyByName(o); err != nil { - return err - } - - n.BondSettings.Uint8(uint16(IFLA_BOND_XMIT_HASH_POLICY), uint8(policy)) - - return err - } -} - -// WithLACPRate configures the bond LACP rate. -func WithLACPRate(o string) Option { - return func(n *NetworkInterface) (err error) { - var rate LACPRate - - if rate, err = LACPRateByName(o); err != nil { - return err - } - - n.BondSettings.Uint8(uint16(IFLA_BOND_AD_LACP_RATE), uint8(rate)) - - return err - } -} - -// WithUpDelay configures the up delay for interfaces that makes up a bond. -// The value is given in ms. -func WithUpDelay(o uint32) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint32(uint16(IFLA_BOND_UPDELAY), o) - - return err - } -} - -// WithDownDelay configures the down delay for interfaces that makes up a bond. -// The value is given in ms. -func WithDownDelay(o uint32) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint32(uint16(IFLA_BOND_DOWNDELAY), o) - - return err - } -} - -// WithMIIMon configures the miimon interval for a bond. -// The value is given in ms. -func WithMIIMon(o uint32) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint32(uint16(IFLA_BOND_MIIMON), o) - - return err - } -} - -// WithUseCarrier configures how miimon will determine the link status. -func WithUseCarrier(o bool) Option { - return func(n *NetworkInterface) (err error) { - // default to 1 - var carrier uint8 = 1 - - if !o { - carrier = 0 - } - - n.BondSettings.Uint8(uint16(IFLA_BOND_USE_CARRIER), carrier) - - return err - } -} - -// WithARPInterval specifies the ARP link monitoring frequency in milliseconds. -func WithARPInterval(o uint32) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint32(uint16(IFLA_BOND_ARP_INTERVAL), o) - - return err - } -} - -// WithARPValidate specifies whether or not ARP probes and replies should be -// validated. -func WithARPValidate(o string) Option { - return func(n *NetworkInterface) (err error) { - var valid ARPValidate - - if valid, err = ARPValidateByName(o); err != nil { - return err - } - - n.BondSettings.Uint32(uint16(IFLA_BOND_ARP_VALIDATE), uint32(valid)) - - return err - } -} - -// WithARPAllTargets specifies the quantity of arp_ip_targets that must be -// reachable in order for the ARP monitor to consider a slave as being up. -func WithARPAllTargets(o string) Option { - return func(n *NetworkInterface) (err error) { - var target ARPAllTargets - - if target, err = ARPAllTargetsByName(o); err != nil { - return err - } - - n.BondSettings.Uint32(uint16(IFLA_BOND_ARP_ALL_TARGETS), uint32(target)) - - return err - } -} - -// WithPrimary specifies which slave is the primary device. -func WithPrimary(o string) Option { - return func(n *NetworkInterface) (err error) { - var iface *net.Interface - - if iface, err = net.InterfaceByName(o); err != nil { - return err - } - - n.BondSettings.Uint8(uint16(IFLA_BOND_PRIMARY_RESELECT), uint8(iface.Index)) - - return err - } -} - -// WithPrimaryReselect specifies the reselection policy for the primary slave. -func WithPrimaryReselect(o string) Option { - return func(n *NetworkInterface) (err error) { - var primary PrimaryReselect - - if primary, err = PrimaryReselectByName(o); err != nil { - return err - } - - n.BondSettings.Uint8(uint16(IFLA_BOND_PRIMARY_RESELECT), uint8(primary)) - - return err - } -} - -// WithFailOverMAC specifies whether active-backup mode should set all -// slaves to the same MAC address. -func WithFailOverMAC(o string) Option { - return func(n *NetworkInterface) (err error) { - var fo FailOverMAC - - if fo, err = FailOverMACByName(o); err != nil { - return err - } - - n.BondSettings.Uint8(uint16(IFLA_BOND_FAIL_OVER_MAC), uint8(fo)) - - return err - } -} - -// WithResendIGMP specifies the number of IGMP membership reports to be issued -// after a failover event. -func WithResendIGMP(o uint32) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint32(uint16(IFLA_BOND_RESEND_IGMP), o) - - return err - } -} - -// WithNumPeerNotif specifies the number of peer notifications (gratuitous ARPs and -// unsolicited IPv6 Neighbor Advertisements) to be issued after a failover event. -func WithNumPeerNotif(o uint8) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint8(uint16(IFLA_BOND_NUM_PEER_NOTIF), o) - - return err - } -} - -// WithAllSlavesActive specifies that duplicate frames (received on inactive -// ports) should be dropped (0) or delivered (1). -func WithAllSlavesActive(o uint8) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint8(uint16(IFLA_BOND_ALL_SLAVES_ACTIVE), o) - - return err - } -} - -// WithMinLinks specifies the minimum number of links that must be active -// before asserting carrier. -func WithMinLinks(o uint32) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint32(uint16(IFLA_BOND_MIN_LINKS), o) - - return err - } -} - -// WithLPInterval specifies the number of seconds between instances where -// the bonding driver sends learning packets to each slaves peer switch. -func WithLPInterval(o uint32) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint32(uint16(IFLA_BOND_LP_INTERVAL), o) - - return err - } -} - -// WithPacketsPerSlave specify the number of packets to transmit through -// a slave before moving to the next one. -func WithPacketsPerSlave(o uint32) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint32(uint16(IFLA_BOND_PACKETS_PER_SLAVE), o) - - return err - } -} - -// WithADSelect specifies the 802.3ad aggregation selection logic to use. -func WithADSelect(o string) Option { - return func(n *NetworkInterface) (err error) { - var sel ADSelect - - if sel, err = ADSelectByName(o); err != nil { - return err - } - - n.BondSettings.Uint8(uint16(IFLA_BOND_AD_SELECT), uint8(sel)) - - return err - } -} - -// WithADActorSysPrio in an AD system, this specifies the system priority. -func WithADActorSysPrio(o uint16) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint16(uint16(IFLA_BOND_AD_ACTOR_SYS_PRIO), o) - - return err - } -} - -// WithADUserPortKey specifies the upper 10 bits of the port key. -func WithADUserPortKey(o uint16) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint16(uint16(IFLA_BOND_AD_USER_PORT_KEY), o) - - return err - } -} - -// WithTLBDynamicLB specifies if dynamic shuffling of flows is enabled in -// tlb mode. -func WithTLBDynamicLB(o uint8) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint8(uint16(IFLA_BOND_TLB_DYNAMIC_LB), o) - - return err - } -} - -// WithPeerNotifyDelay specifies the delay between each peer notification -// (gratuitous ARP and unsolicited IPv6 Neighbor Advertisement) when they -// are issued after a failover event. -// The value is given in ms. -func WithPeerNotifyDelay(o uint32) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Uint32(uint16(IFLA_BOND_PEER_NOTIF_DELAY), o) - - return err - } -} - -/* -// o = mac addr -// [IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NLA_BINARY, .len = ETH_ALEN }, -func WithADActorSystem(o string) Option { - return func(n *NetworkInterface) (err error) { - return err - } -} - -// Not sure this is the right way to do nested attributes -func WithARPIPTarget(o []string) Option { - return func(n *NetworkInterface) (err error) { - n.BondSettings.Nested(uint16(IFLA_BOND_ARP_IP_TARGET), netlink.NewAttributeEncoder().String(uint16(IFLA_BOND_ARP_IP_TARGET), strings.Join(",", o))) - return err - } -} - -// [IFLA_BOND_AD_INFO] = { .type = NLA_NESTED }, -// func WithInfo(o []string) Option { - -// Not adding Active Slave since this is more of a -// runtime adjustment versus config -// [IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 }, -*/ diff --git a/internal/app/networkd/pkg/nic/netlink.go b/internal/app/networkd/pkg/nic/netlink.go deleted file mode 100644 index df2853217..000000000 --- a/internal/app/networkd/pkg/nic/netlink.go +++ /dev/null @@ -1,152 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package nic - -import ( - "net" - - "github.com/jsimonetti/rtnetlink" - "github.com/mdlayher/netlink" - "golang.org/x/sys/unix" - "golang.zx2c4.com/wireguard/wgctrl" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -// createLink creates an interface. -func (n *NetworkInterface) createLink(name string, info *rtnetlink.LinkInfo) error { - err := n.rtConn.Link.New(&rtnetlink.LinkMessage{ - Family: unix.AF_UNSPEC, - Type: 0, - Attributes: &rtnetlink.LinkAttributes{ - Name: name, - Info: info, - }, - }) - - return err -} - -// createLink creates an interface. -func (n *NetworkInterface) createSubLink(name string, info *rtnetlink.LinkInfo, master *uint32) error { - err := n.rtConn.Link.New(&rtnetlink.LinkMessage{ - Family: unix.AF_UNSPEC, - Type: 0, - Attributes: &rtnetlink.LinkAttributes{ - Name: name, - Info: info, - Type: *master, - }, - }) - - return err -} - -// setMTU sets the link MTU. -func (n *NetworkInterface) setMTU(idx int, mtu uint32) error { - msg, err := n.rtConn.Link.Get(uint32(idx)) - if err != nil { - return err - } - - if msg.Attributes != nil && msg.Attributes.MTU == mtu { - return nil - } - - err = n.rtConn.Link.Set(&rtnetlink.LinkMessage{ - Family: msg.Family, - Type: msg.Type, - Index: uint32(idx), - Flags: msg.Flags, - Change: 0, - Attributes: &rtnetlink.LinkAttributes{ - MTU: mtu, - }, - }) - - return err -} - -func (n *NetworkInterface) configureBond(idx int, attrs *netlink.AttributeEncoder) error { - // Request the details of the interface - msg, err := n.rtConn.Link.Get(uint32(idx)) - if err != nil { - return err - } - - nlAttrBytes, err := attrs.Encode() - if err != nil { - return err - } - - err = n.rtConn.Link.Set(&rtnetlink.LinkMessage{ - Family: unix.AF_UNSPEC, - Type: msg.Type, - Index: msg.Index, - Change: 0, - Attributes: &rtnetlink.LinkAttributes{ - Info: &rtnetlink.LinkInfo{ - // https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/if_link.h#L612 - Kind: "bond", - Data: nlAttrBytes, - }, - }, - }) - if err != nil { - return err - } - - return nil -} - -func (n *NetworkInterface) configureWireguard(name string, config *wgtypes.Config) error { - c, err := wgctrl.New() - if err != nil { - return err - } - - defer c.Close() //nolint:errcheck - - return c.ConfigureDevice(name, *config) -} - -func (n *NetworkInterface) enslaveLink(bondIndex *uint32, links ...*net.Interface) error { - // Set the interface operationally UP - for _, iface := range links { - // Request the details of the interface - msg, err := n.rtConn.Link.Get(uint32(iface.Index)) - if err != nil { - return err - } - - // rtnl.Down - err = n.rtConn.Link.Set(&rtnetlink.LinkMessage{ - Family: msg.Family, - Type: msg.Type, - Index: uint32(iface.Index), - Flags: 0, - Change: unix.IFF_UP, - }) - if err != nil { - return err - } - - // Set link master to bond interface - err = n.rtConn.Link.Set(&rtnetlink.LinkMessage{ - Family: msg.Family, - Type: msg.Type, - Index: uint32(iface.Index), - Change: 0, - Flags: 0, - Attributes: &rtnetlink.LinkAttributes{ - Master: bondIndex, - }, - }) - if err != nil { - return err - } - } - - return nil -} diff --git a/internal/app/networkd/pkg/nic/nic.go b/internal/app/networkd/pkg/nic/nic.go deleted file mode 100644 index ffbbbacfa..000000000 --- a/internal/app/networkd/pkg/nic/nic.go +++ /dev/null @@ -1,486 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// Package nic provides a way to describe and configure a network interface. -package nic - -import ( - "context" - "errors" - "fmt" - "log" - "net" - "os" - "strconv" - "syscall" - "time" - - "github.com/hashicorp/go-multierror" - "github.com/jsimonetti/rtnetlink" - "github.com/jsimonetti/rtnetlink/rtnl" - "github.com/mdlayher/netlink" - "github.com/talos-systems/go-procfs/procfs" - "github.com/talos-systems/go-retry/retry" - "golang.org/x/sync/errgroup" - "golang.org/x/sys/unix" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" - "google.golang.org/protobuf/proto" - - "github.com/talos-systems/talos/internal/app/networkd/pkg/address" - "github.com/talos-systems/talos/internal/app/networkd/pkg/vip" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -const ( - // ref: https://tools.ietf.org/html/rfc791 - - // MinimumMTU is the lowest allowed MTU for an interface. - MinimumMTU = 68 - // MaximumMTU is the highest allowed MTU for an interface. - MaximumMTU = 65536 -) - -// NetworkInterface provides an abstract configuration representation for a -// network interface. -type NetworkInterface struct { - Name string - Type int - Ignore bool - Dummy bool - Bonded bool - Wireguard bool - MTU uint32 - Link *net.Interface - SubInterfaces []*net.Interface - AddressMethod []address.Addressing - BondSettings *netlink.AttributeEncoder - Vlans []*Vlan - VirtualIP net.IP - WireguardConfig *wgtypes.Config - - rtConn *rtnetlink.Conn - rtnlConn *rtnl.Conn - - vipController vip.Controller -} - -// New returns a NetworkInterface with all of the given setter options applied. -func New(setters ...Option) (*NetworkInterface, error) { - // Default interface setup - iface := defaultOptions() - - // Configure interface with any specified options - var result *multierror.Error - for _, setter := range setters { - result = multierror.Append(result, setter(iface)) - } - - // TODO: May need to look at switching this around to filter by Interface.HardwareAddr - // Ensure we have an interface name defined - if iface.Name == "" { - result = multierror.Append(result, errors.New("interface must have a name")) - } - - // If no addressing methods have been configured, default to DHCP. - // If VLANs exist do not force DHCP on master device - if len(iface.AddressMethod) == 0 && len(iface.Vlans) == 0 { - iface.AddressMethod = append(iface.AddressMethod, &address.DHCP4{}) // TODO: enable DHCPv6 by default? - } - - // Handle netlink connection - conn, err := rtnl.Dial(nil) - if err != nil { - result = multierror.Append(result, err) - - return nil, result.ErrorOrNil() - } - - iface.rtnlConn = conn - - // Need rtnetlink for MTU and bond settings - nlConn, err := rtnetlink.Dial(nil) - if err != nil { - result = multierror.Append(result, err) - - return nil, result.ErrorOrNil() - } - - iface.rtConn = nlConn - - return iface, result.ErrorOrNil() -} - -// IsIgnored checks the network interface to see if it should be ignored and not configured. -func (n *NetworkInterface) IsIgnored() bool { - if n.Ignore || procfs.ProcCmdline().Get(constants.KernelParamNetworkInterfaceIgnore).Contains(n.Name) { - return true - } - - return false -} - -// Create creates the underlying link if it does not already exist. -func (n *NetworkInterface) Create() error { - var info *rtnetlink.LinkInfo - - iface, err := net.InterfaceByName(n.Name) - if err == nil { - n.Link = iface - - return nil - } - - switch { - case n.Bonded: - info = &rtnetlink.LinkInfo{Kind: "bond"} - case n.Dummy: - info = &rtnetlink.LinkInfo{Kind: "dummy"} - case n.Wireguard: - info = &rtnetlink.LinkInfo{Kind: "wireguard"} - default: - return fmt.Errorf("unknown device type") - } - - if err = n.createLink(n.Name, info); err != nil { - return err - } - - iface, err = net.InterfaceByName(n.Name) - - if err != nil { - return err - } - - n.Link = iface - - return nil -} - -// CreateSub create VLAN devices that belongs to a master device. -func (n *NetworkInterface) CreateSub(logger *log.Logger) error { - var info *rtnetlink.LinkInfo - - // Create all the VLAN devices - for _, vlan := range n.Vlans { - name := n.Name + "." + strconv.Itoa(int(vlan.ID)) - logger.Printf("setting up %s", name) - iface, err := net.InterfaceByName(name) - - if err == nil { - vlan.Link = iface - - continue - } - - data, err := vlan.VlanSettings.Encode() - if err != nil { - logger.Println("failed to encode vlan link parameters: " + err.Error()) - - continue - } - - // Vlan devices needs the master link index - masterIdx := uint32(n.Link.Index) - info = &rtnetlink.LinkInfo{Kind: "vlan", Data: data} - - if err = n.createSubLink(name, info, &masterIdx); err != nil { - logger.Println("failed to create vlan link " + err.Error()) - - return err - } - - iface, err = net.InterfaceByName(name) - if err != nil { - logger.Println("failed to get vlan interface ") - - return err - } - - vlan.Link = iface - } - - return nil -} - -// Configure is used to set the link state and configure any necessary -// bond settings ( ex, mode ). -//nolint:gocyclo -func (n *NetworkInterface) Configure(ctx context.Context) (err error) { - if n.IsIgnored() { - return err - } - - if n.Bonded { - if err = n.configureBond(n.Link.Index, n.BondSettings); err != nil { - return err - } - - bondIndex := proto.Uint32(uint32(n.Link.Index)) - - // TODO: Add check if link is already part of a bond - if err = n.enslaveLink(bondIndex, n.SubInterfaces...); err != nil { - return err - } - } - - if n.Wireguard { - if err = n.configureWireguard(n.Name, n.WireguardConfig); err != nil { - return err - } - } - - if err = n.rtnlConn.LinkUp(n.Link); err != nil { - return err - } - - if err = n.waitForLinkToBeUp(n.Link); err != nil { - return fmt.Errorf("failed to bring up interface %q: %w", n.Link.Name, err) - } - - // Create all the VLAN devices - for _, vlan := range n.Vlans { - if err = n.rtnlConn.LinkUp(vlan.Link); err != nil { - return err - } - - if err = n.waitForLinkToBeUp(vlan.Link); err != nil { - return fmt.Errorf("failed to bring up interface %q: %w", vlan.Link.Name, err) - } - } - - return nil -} - -// RunControllers is used to run additional controllers per interface. -func (n *NetworkInterface) RunControllers(ctx context.Context, logger *log.Logger, eg *errgroup.Group) (err error) { - if n.VirtualIP != nil { - if n.vipController, err = vip.New(n.VirtualIP.String(), n.Link.Name); err != nil { - return fmt.Errorf("failed to create the VirtualIP controller for %q on %q: %w", n.VirtualIP, n.Link.Name, err) - } - - if err = n.vipController.Start(ctx, logger, eg); err != nil { - return fmt.Errorf("failed to start the VirtualIP controller for %q on %q: %w", n.VirtualIP, n.Link.Name, err) - } - } - - return nil -} - -func (n *NetworkInterface) waitForLinkToBeUp(linkDev *net.Interface) error { - // Wait for link to report up - var link rtnetlink.LinkMessage - - err := retry.Constant(30*time.Second, retry.WithUnits(250*time.Millisecond), retry.WithJitter(50*time.Millisecond)).Retry(func() error { - var err error - link, err = n.rtConn.Link.Get(uint32(linkDev.Index)) - if err != nil { - return err - } - - if link.Flags&unix.IFF_UP != unix.IFF_UP { - return retry.ExpectedError(fmt.Errorf("link is not up %s", n.Link.Name)) - } - - if link.Flags&unix.IFF_RUNNING != unix.IFF_RUNNING { - return retry.ExpectedError(fmt.Errorf("link is not ready %s", n.Link.Name)) - } - - return nil - }) - - return err -} - -// Addressing handles the address method for a configured interface ( dhcp/static ). -// This is inclusive of the address itself as well as any defined routes. -func (n *NetworkInterface) Addressing(logger *log.Logger) error { - if n.IsIgnored() { - return nil - } - - for _, method := range n.AddressMethod { - if err := n.configureInterface(logger, method, n.Link); err != nil { - // Treat as non fatal error when failing to configure an interface - continue - } - } - - return nil -} - -// AddressingSub handles the address method for a configured sub interface ( dhcp/static ). -// This is inclusive of the address itself as well as any defined routes. -func (n *NetworkInterface) AddressingSub(logger *log.Logger) error { - if n.IsIgnored() { - return nil - } - - for _, vlan := range n.Vlans { - for _, method := range vlan.AddressMethod { - if err := n.configureInterface(logger, method, vlan.Link); err != nil { - logger.Println("failed to configure address on vlan link: " + err.Error()) - // Treat as non fatal error when failing to configure an interface - continue - } - } - } - - return nil -} - -// Renew is the mechanism for keeping a dhcp lease active. -func (n *NetworkInterface) Renew(ctx context.Context, logger *log.Logger) { - for _, method := range n.AddressMethod { - if method.TTL() == 0 { - continue - } - - go n.renew(ctx, logger, method) - } -} - -// renew sets up the looping to ensure we keep the addressing information -// up to date. We attempt to do our first reconfiguration halfway through -// address TTL. If that fails, we'll continue to attempt to retry every -// halflife. -func (n *NetworkInterface) renew(ctx context.Context, logger *log.Logger, method address.Addressing) { - const minRenewDuration = 5 * time.Second // protect from renewing too often - - renewDuration := method.TTL() / 2 - - var err error - - for { - select { - case <-time.After(renewDuration): - case <-ctx.Done(): - return - } - - if err = n.configureInterface(logger, method, n.Link); err != nil { - logger.Printf("failure to renew address for %q: %s", n.Name, err) - - renewDuration = (renewDuration / 2) - } else { - renewDuration = method.TTL() / 2 - } - - if renewDuration < minRenewDuration { - renewDuration = minRenewDuration - } - } -} - -// configureInterface handles the actual address discovery mechanism and -// netlink interaction to configure the interface. -//nolint:gocyclo,cyclop -func (n *NetworkInterface) configureInterface(logger *log.Logger, method address.Addressing, link *net.Interface) error { - var err error - - discoverErr := method.Discover(context.Background(), logger, link) - - // Set link MTU in any case - if err = n.setMTU(method.Link().Index, method.MTU()); err != nil { - return fmt.Errorf("error setting MTU %d on %q: %w", method.MTU(), n.Name, err) - } - - if discoverErr != nil { - return discoverErr - } - - if method.Address() != nil { - // Check to see if we need to configure the address - var addrs []*net.IPNet - - addrs, err = n.rtnlConn.Addrs(method.Link(), method.Family()) - if err != nil { - return err - } - - addressExists := false - - for _, addr := range addrs { - if method.Address().String() == addr.String() { - addressExists = true - - break - } - } - - if !addressExists && method.Address() != nil { - if err = n.rtnlConn.AddrAdd(method.Link(), method.Address()); err != nil { - switch err := err.(type) { - case *netlink.OpError: - if !os.IsExist(err.Err) && err.Err != syscall.ESRCH { - return fmt.Errorf("error adding address %s on %q: %w", method.Address(), n.Name, err) - } - default: - return fmt.Errorf("failed to add address (already exists) %+v to %s: %v", method.Address(), method.Link().Name, err) - } - } - } - } - - // Add any routes - for _, r := range method.Routes() { - // If gateway/router is 0.0.0.0 we'll set to nil so route scope decision will be correct - gw := r.Gateway - if net.IPv4zero.Equal(gw) || net.IPv6zero.Equal(gw) { - gw = nil - } - - src := method.Address() - // if destination is the ipv6 default route,and gateway is LL do not pass a src address to set the default geteway - if net.IPv6zero.Equal(r.Destination.IP) && gw.IsLinkLocalUnicast() { - src = nil - } - - attr := rtnetlink.RouteAttributes{ - Dst: r.Destination.IP, - OutIface: uint32(method.Link().Index), - Priority: r.Metric, - } - - if gw != nil { - attr.Gateway = gw - } - - err = n.rtnlConn.RouteAdd(method.Link(), *r.Destination, gw, rtnl.WithRouteSrc(src), rtnl.WithRouteAttrs(attr)) - if err != nil { - // ignore "EEXIST" errors for routes which are already present - if opErr, ok := err.(*netlink.OpError); !ok || !os.IsExist(opErr.Err) { - return fmt.Errorf("error adding route %s %s on %q: %s", *r.Destination, gw, n.Name, err) - } - } - } - - return nil -} - -// Reset removes addressing configuration from a given link. -func (n *NetworkInterface) Reset() { - var ( - err error - link *net.Interface - nets []*net.IPNet - ) - - link, err = net.InterfaceByName(n.Name) - if err != nil { - return - } - - if nets, err = n.rtnlConn.Addrs(link, 0); err != nil { - return - } - - for _, ipnet := range nets { - if err = n.rtnlConn.AddrDel(link, ipnet); err != nil { - continue - } - } - - //nolint:errcheck - n.rtnlConn.LinkDown(link) -} diff --git a/internal/app/networkd/pkg/nic/nic_test.go b/internal/app/networkd/pkg/nic/nic_test.go deleted file mode 100644 index c7bed70e3..000000000 --- a/internal/app/networkd/pkg/nic/nic_test.go +++ /dev/null @@ -1,128 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package nic_test - -import ( - "testing" - - "github.com/stretchr/testify/suite" - - "github.com/talos-systems/talos/internal/app/networkd/pkg/address" - "github.com/talos-systems/talos/internal/app/networkd/pkg/nic" - "github.com/talos-systems/talos/pkg/machinery/config" -) - -type NicSuite struct { - suite.Suite -} - -func TestNicSuite(t *testing.T) { - suite.Run(t, new(NicSuite)) -} - -func (suite *NicSuite) TestIgnoreNic() { - mynic, err := nic.New(nic.WithName("yolo"), nic.WithIgnore()) - - suite.Require().NoError(err) - suite.Assert().True(mynic.IsIgnored()) -} - -func (suite *NicSuite) TestNoName() { - _, err := nic.New() - suite.Require().Error(err) -} - -func (suite *NicSuite) TestBond() { - testSettings := [][]nic.Option{ - { - nic.WithName("yolobond"), - nic.WithBond(true), - }, - { - nic.WithName("yolobond"), - nic.WithBond(true), - nic.WithBondMode("balance-xor"), - }, - { - nic.WithName("yolobond"), - nic.WithBond(true), - nic.WithBondMode("802.3ad"), - nic.WithHashPolicy("layer3+4"), - }, - { - nic.WithName("yolobond"), - nic.WithBond(true), - nic.WithBondMode("balance-tlb"), - nic.WithHashPolicy("encap3+4"), - nic.WithLACPRate("fast"), - }, - { - nic.WithName("yolobond"), - nic.WithBond(true), - nic.WithBondMode("balance-alb"), - nic.WithHashPolicy("encap2+3"), - nic.WithLACPRate("slow"), - nic.WithUpDelay(200), - }, - { - nic.WithName("yolobond"), - nic.WithBond(true), - nic.WithBondMode("broadcast"), - nic.WithHashPolicy("layer2+3"), - nic.WithLACPRate("fast"), - nic.WithUpDelay(300), - nic.WithDownDelay(400), - nic.WithMIIMon(500), - }, - { - nic.WithName("yolobond"), - nic.WithBond(true), - nic.WithBondMode("balance-rr"), - nic.WithHashPolicy("layer2"), - nic.WithLACPRate("slow"), - nic.WithUpDelay(300), - nic.WithDownDelay(400), - nic.WithMIIMon(500), - nic.WithSubInterface("lo", "lo"), - }, - { - nic.WithName("yolobond"), - nic.WithBond(true), - nic.WithBondMode("active-backup"), - nic.WithHashPolicy("layer2"), - nic.WithLACPRate("slow"), - nic.WithUpDelay(300), - nic.WithDownDelay(400), - nic.WithMIIMon(500), - nic.WithSubInterface("lo", "lo"), - nic.WithAddressing(&address.Static{}), - }, - } - - for _, test := range testSettings { - mynic, err := nic.New(test...) - suite.Require().NoError(err) - suite.Assert().True(mynic.Bonded) - } -} - -func (suite *NicSuite) TestVlan() { - testSettings := [][]nic.Option{ - { - nic.WithName("eth0"), - nic.WithVlan(100), - }, - { - nic.WithName("eth0"), - nic.WithVlan(100), - nic.WithVlanCIDR(100, "172.21.10.101/28", []config.Route{}), - }, - } - for _, test := range testSettings { - mynic, err := nic.New(test...) - suite.Require().NoError(err) - suite.Assert().True(len(mynic.Vlans) > 0) - } -} diff --git a/internal/app/networkd/pkg/nic/options.go b/internal/app/networkd/pkg/nic/options.go deleted file mode 100644 index 4ff33aa4f..000000000 --- a/internal/app/networkd/pkg/nic/options.go +++ /dev/null @@ -1,71 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package nic - -import ( - "github.com/mdlayher/netlink" - - "github.com/talos-systems/talos/internal/app/networkd/pkg/address" -) - -// Option is the functional option func. -type Option func(*NetworkInterface) error - -// defaultOptions defines our default network interface configuration. -func defaultOptions() *NetworkInterface { - return &NetworkInterface{ - Bonded: false, - MTU: 1500, - AddressMethod: []address.Addressing{}, - BondSettings: netlink.NewAttributeEncoder(), - } -} - -// WithDummy indicates that the interface should be a virtual, dummy interface. -func WithDummy() Option { - return func(n *NetworkInterface) (err error) { - n.Dummy = true - - return - } -} - -// WithIgnore indicates that the interface should not be processed by talos. -func WithIgnore() Option { - return func(n *NetworkInterface) (err error) { - n.Ignore = true - - return - } -} - -// WithName sets the name of the interface to the given name. -func WithName(o string) Option { - return func(n *NetworkInterface) (err error) { - n.Name = o - - return err - } -} - -// WithAddressing defines how the addressing for a given interface -// should be configured. -func WithAddressing(a address.Addressing) Option { - return func(n *NetworkInterface) (err error) { - n.AddressMethod = append(n.AddressMethod, a) - - return err - } -} - -// WithNoAddressing defines how the addressing for a given interface -// should be configured. -func WithNoAddressing() Option { - return func(n *NetworkInterface) (err error) { - n.AddressMethod = []address.Addressing{} - - return err - } -} diff --git a/internal/app/networkd/pkg/nic/vars.go b/internal/app/networkd/pkg/nic/vars.go deleted file mode 100644 index a7fc26ee3..000000000 --- a/internal/app/networkd/pkg/nic/vars.go +++ /dev/null @@ -1,322 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -//nolint:golint,stylecheck,revive -package nic - -import "fmt" - -// https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/if_link.h#L608 -type BondSetting uint16 - -const ( - IFLA_BOND_UNSPEC BondSetting = iota - IFLA_BOND_MODE - IFLA_BOND_ACTIVE_SLAVE - IFLA_BOND_MIIMON - IFLA_BOND_UPDELAY - IFLA_BOND_DOWNDELAY - IFLA_BOND_USE_CARRIER - IFLA_BOND_ARP_INTERVAL - IFLA_BOND_ARP_IP_TARGET - IFLA_BOND_ARP_VALIDATE - IFLA_BOND_ARP_ALL_TARGETS - IFLA_BOND_PRIMARY - IFLA_BOND_PRIMARY_RESELECT - IFLA_BOND_FAIL_OVER_MAC - IFLA_BOND_XMIT_HASH_POLICY - IFLA_BOND_RESEND_IGMP - IFLA_BOND_NUM_PEER_NOTIF - IFLA_BOND_ALL_SLAVES_ACTIVE - IFLA_BOND_MIN_LINKS - IFLA_BOND_LP_INTERVAL - IFLA_BOND_PACKETS_PER_SLAVE - IFLA_BOND_AD_LACP_RATE - IFLA_BOND_AD_SELECT - IFLA_BOND_AD_INFO - IFLA_BOND_AD_ACTOR_SYS_PRIO - IFLA_BOND_AD_USER_PORT_KEY - IFLA_BOND_AD_ACTOR_SYSTEM - IFLA_BOND_TLB_DYNAMIC_LB - IFLA_BOND_PEER_NOTIF_DELAY -) - -func (b BondSetting) String() string { - return [...]string{ - "unspec", - "mode", - "active slave", - "miimon", - "updelay", - "downdelay", - "use carrier", - "arp interval", - "arp ip target", - "arp validate", - "arp all targets", - "primary", - "primary reselect", - "fail over mac", - "xmit hash policy", - "resend igmp", - "num peer notif", - "all slaves active", - "min links", - "lp interval", - "packets per slave", - "ad lacp rate", - "ad select", - "ad innfo", - "ad actor sys prio", - "ad user port key", - "ad actor system", - "tlb dynamic lb", - "peer notif delay", - }[int(b)] -} - -// https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/if_bonding.h -type BondMode uint8 - -const ( - BOND_MODE_ROUNDROBIN BondMode = iota - BOND_MODE_ACTIVEBACKUP - BOND_MODE_XOR - BOND_MODE_BROADCAST - BOND_MODE_8023AD - BOND_MODE_TLB - BOND_MODE_ALB -) - -func (b BondMode) String() string { - return [...]string{"balance-rr", "active-backup", "balance-xor", "broadcast", "802.3ad", "balance-tlb", "balance-alb"}[int(b)] -} - -func BondModeByName(mode string) (bm BondMode, err error) { - switch mode { - case "balance-rr": - bm = BOND_MODE_ROUNDROBIN - case "active-backup": - bm = BOND_MODE_ACTIVEBACKUP - case "balance-xor": - bm = BOND_MODE_XOR - case "broadcast": - bm = BOND_MODE_BROADCAST - case "802.3ad": - bm = BOND_MODE_8023AD - case "balance-tlb": - bm = BOND_MODE_TLB - case "balance-alb": - bm = BOND_MODE_ALB - default: - err = fmt.Errorf("invalid bond type %s", mode) - } - - return bm, err -} - -type BondXmitHashPolicy uint8 - -const ( - BOND_XMIT_POLICY_LAYER2 BondXmitHashPolicy = iota - BOND_XMIT_POLICY_LAYER34 - BOND_XMIT_POLICY_LAYER23 - BOND_XMIT_POLICY_ENCAP23 - BOND_XMIT_POLICY_ENCAP34 -) - -func (b BondXmitHashPolicy) String() string { - return [...]string{"layer2", "layer3+4", "layer2+3", "encap2+3", "encap3+4"}[int(b)] -} - -func BondXmitHashPolicyByName(policy string) (xmit BondXmitHashPolicy, err error) { - switch policy { - case "layer2": - xmit = BOND_XMIT_POLICY_LAYER2 - case "layer3+4": - xmit = BOND_XMIT_POLICY_LAYER34 - case "layer2+3": - xmit = BOND_XMIT_POLICY_LAYER23 - case "encap2+3": - xmit = BOND_XMIT_POLICY_ENCAP23 - case "encap3+4": - xmit = BOND_XMIT_POLICY_ENCAP34 - default: - err = fmt.Errorf("invalid xmit hash policy %v", xmit) - } - - return xmit, err -} - -type LACPRate uint8 - -const ( - LACP_RATE_SLOW LACPRate = iota - LACP_RATE_FAST -) - -func (l LACPRate) String() string { - return [...]string{"slow", "fast"}[l] -} - -func LACPRateByName(mode string) (rate LACPRate, err error) { - switch mode { - case "slow": - rate = LACP_RATE_SLOW - case "fast": - rate = LACP_RATE_FAST - default: - err = fmt.Errorf("invalid lacp rate %v", mode) - } - - return rate, err -} - -type ADSelect uint8 - -const ( - AD_SELECT_STABLE ADSelect = iota - AD_SELECT_BANDWIDTH - AD_SELECT_COUNT -) - -func (a ADSelect) String() string { - return [...]string{"stable", "bandwidth", "count"}[a] -} - -func ADSelectByName(sel string) (adsel ADSelect, err error) { - switch sel { - case "stable": - adsel = AD_SELECT_STABLE - case "bandwidth": - adsel = AD_SELECT_BANDWIDTH - case "count": - adsel = AD_SELECT_COUNT - default: - err = fmt.Errorf("invalid ad_select mode %v", sel) - } - - return adsel, err -} - -type ARPValidate uint32 - -const ( - ARP_VALIDATE_NONE ARPValidate = iota - ARP_VALIDATE_ACTIVE - ARP_VALIDATE_BACKUP - ARP_VALIDATE_ALL -) - -func (a ARPValidate) String() string { - return [...]string{"none", "active", "backup", "all"}[a] -} - -func ARPValidateByName(a string) (arpv ARPValidate, err error) { - switch a { - case "none": - arpv = ARP_VALIDATE_NONE - case "active": - arpv = ARP_VALIDATE_ACTIVE - case "backup": - arpv = ARP_VALIDATE_BACKUP - case "all": - arpv = ARP_VALIDATE_ALL - default: - err = fmt.Errorf("invalid arp_validate mode %v", a) - } - - return arpv, err -} - -type ARPAllTargets uint32 - -const ( - ARP_ALL_TARGETS_ANY ARPAllTargets = iota - ARP_ALL_TARGETS_ALL -) - -func (a ARPAllTargets) String() string { - return [...]string{"any", "all"}[a] -} - -func ARPAllTargetsByName(a string) (arpa ARPAllTargets, err error) { - switch a { - case "any": - arpa = ARP_ALL_TARGETS_ANY - case "all": - arpa = ARP_ALL_TARGETS_ALL - default: - err = fmt.Errorf("invalid arp_all_targets mode %v", a) - } - - return arpa, err -} - -type PrimaryReselect uint8 - -const ( - PRIMARY_RESELECT_ALWAYS PrimaryReselect = iota - PRIMARY_RESELECT_BETTER - PRIMARY_RESELECT_FAILURE -) - -func (p PrimaryReselect) String() string { - return [...]string{"always", "better", "failure"}[p] -} - -func PrimaryReselectByName(p string) (pr PrimaryReselect, err error) { - switch p { - case "always": - pr = PRIMARY_RESELECT_ALWAYS - case "better": - pr = PRIMARY_RESELECT_BETTER - case "failure": - pr = PRIMARY_RESELECT_FAILURE - default: - err = fmt.Errorf("invalid primary_reselect mode %v", p) - } - - return pr, err -} - -type FailOverMAC uint8 - -const ( - FAIL_OVER_MAC_NONE FailOverMAC = iota - FAIL_OVER_MAC_ACTIVE - FAIL_OVER_MAC_FOLLOW -) - -func FailOverMACByName(f string) (fo FailOverMAC, err error) { - switch f { - case "none": - fo = FAIL_OVER_MAC_NONE - case "active": - fo = FAIL_OVER_MAC_ACTIVE - case "follow": - fo = FAIL_OVER_MAC_FOLLOW - default: - err = fmt.Errorf("invalid fail_over_mac value %v", f) - } - - return fo, err -} - -const ( - IFLA_VLAN_UNSPEC = iota - IFLA_VLAN_ID - IFLA_VLAN_FLAGS - IFLA_VLAN_EGRESS_QOS - IFLA_VLAN_INGRESS_QOS - IFLA_VLAN_PROTOCOL - IFLA_VLAN_MAX = IFLA_VLAN_PROTOCOL -) - -// VlanProtocol possible values. -const ( - VLAN_PROTOCOL_UNKNOWN = 0 - VLAN_PROTOCOL_8021Q = 0x8100 - VLAN_PROTOCOL_8021AD = 0x88A8 -) diff --git a/internal/app/networkd/pkg/nic/vip_options.go b/internal/app/networkd/pkg/nic/vip_options.go deleted file mode 100644 index a47f1187a..000000000 --- a/internal/app/networkd/pkg/nic/vip_options.go +++ /dev/null @@ -1,29 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// Additional information can be found -// https://www.kernel.org/doc/Documentation/networking/bonding.txt. - -package nic - -import ( - "fmt" - "net" - - "github.com/talos-systems/talos/pkg/machinery/config" -) - -// WithVIPConfig adapts a talosconfig VIP configuration to a networkd interface configuration option. -func WithVIPConfig(cfg config.VIPConfig) Option { - return func(n *NetworkInterface) (err error) { - sharedIP := net.ParseIP(cfg.IP()) - if sharedIP == nil { - return fmt.Errorf("failed to parse shared IP %q as an IP address", cfg.IP()) - } - - n.VirtualIP = sharedIP - - return nil - } -} diff --git a/internal/app/networkd/pkg/nic/vlan_options.go b/internal/app/networkd/pkg/nic/vlan_options.go deleted file mode 100644 index 4e3b2c0f6..000000000 --- a/internal/app/networkd/pkg/nic/vlan_options.go +++ /dev/null @@ -1,75 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package nic - -import ( - "fmt" - "net" - - "github.com/mdlayher/netlink" - - "github.com/talos-systems/talos/internal/app/networkd/pkg/address" - "github.com/talos-systems/talos/pkg/machinery/config" -) - -// Vlan contins interface related parameters to a VLAN device. -type Vlan struct { - Parent string - ID uint16 - Link *net.Interface - VlanSettings *netlink.AttributeEncoder - AddressMethod []address.Addressing -} - -// WithVlan defines the VLAN id to use. -func WithVlan(id uint16) Option { - return func(n *NetworkInterface) (err error) { - for _, vlan := range n.Vlans { - if vlan.ID == id { - return fmt.Errorf("duplicate VLAN id %v given", vlan) - } - } - - vlan := &Vlan{ - ID: id, - VlanSettings: netlink.NewAttributeEncoder(), - } - - vlan.VlanSettings.Uint16(uint16(IFLA_VLAN_ID), vlan.ID) - n.Vlans = append(n.Vlans, vlan) - - return nil - } -} - -// WithVlanDhcp sets a VLAN device with DHCP. -func WithVlanDhcp(id uint16) Option { - return func(n *NetworkInterface) (err error) { - for _, vlan := range n.Vlans { - if vlan.ID == id { - vlan.AddressMethod = append(vlan.AddressMethod, &address.DHCP4{}) // TODO: should we enable DHCP6 by default? - - return nil - } - } - - return fmt.Errorf("VLAN id not found for DHCP. Vlan ID %v given", id) - } -} - -// WithVlanCIDR defines if the interface have static CIDRs added. -func WithVlanCIDR(id uint16, cidr string, routeList []config.Route) Option { - return func(n *NetworkInterface) (err error) { - for _, vlan := range n.Vlans { - if vlan.ID == id { - vlan.AddressMethod = append(vlan.AddressMethod, &address.Static{CIDR: cidr, RouteList: routeList}) - - return nil - } - } - - return fmt.Errorf("VLAN id not found for CIDR setting %v given", id) - } -} diff --git a/internal/app/networkd/pkg/nic/wireguard.go b/internal/app/networkd/pkg/nic/wireguard.go deleted file mode 100644 index b92641453..000000000 --- a/internal/app/networkd/pkg/nic/wireguard.go +++ /dev/null @@ -1,87 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// Additional information can be found -// https://www.kernel.org/doc/Documentation/networking/bonding.txt. - -package nic - -import ( - "net" - - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" - - "github.com/talos-systems/talos/pkg/machinery/config" -) - -// WithWireguardConfig defines if the interface should be a Wireguard interface and supplies Wireguard configs. -//nolint:gocyclo -func WithWireguardConfig(cfg config.WireguardConfig) Option { - return func(n *NetworkInterface) (err error) { - n.Wireguard = true - - privateKey, err := wgtypes.ParseKey(cfg.PrivateKey()) - if err != nil { - return err - } - - config := &wgtypes.Config{ - PrivateKey: &privateKey, - ReplacePeers: true, - } - - firewallMark := cfg.FirewallMark() - if firewallMark > 0 { - config.FirewallMark = &firewallMark - } - - listenPort := cfg.ListenPort() - - if listenPort > 0 { - config.ListenPort = &listenPort - } - - config.Peers = make([]wgtypes.PeerConfig, len(cfg.Peers())) - - for i, peer := range cfg.Peers() { - publicKey, err := wgtypes.ParseKey(peer.PublicKey()) - if err != nil { - return err - } - - peerCfg := wgtypes.PeerConfig{ - PublicKey: publicKey, - AllowedIPs: make([]net.IPNet, len(peer.AllowedIPs())), - } - - if peer.Endpoint() != "" { - peerCfg.Endpoint, err = net.ResolveUDPAddr("", peer.Endpoint()) - if err != nil { - return err - } - } - - peerKeepaliveInterval := peer.PersistentKeepaliveInterval() - - if peerKeepaliveInterval > 0 { - peerCfg.PersistentKeepaliveInterval = &peerKeepaliveInterval - } - - for j, ip := range peer.AllowedIPs() { - _, ip, err := net.ParseCIDR(ip) - if err != nil { - return err - } - - peerCfg.AllowedIPs[j] = *ip - } - - config.Peers[i] = peerCfg - } - - n.WireguardConfig = config - - return nil - } -} diff --git a/internal/app/networkd/pkg/reg/reg.go b/internal/app/networkd/pkg/reg/reg.go deleted file mode 100644 index ff7416f13..000000000 --- a/internal/app/networkd/pkg/reg/reg.go +++ /dev/null @@ -1,102 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// Package reg provides the gRPC network service implementation. -package reg - -import ( - "context" - "errors" - "time" - - "github.com/golang/protobuf/ptypes/empty" - "google.golang.org/grpc" - - "github.com/talos-systems/talos/internal/app/networkd/pkg/networkd" - healthapi "github.com/talos-systems/talos/pkg/machinery/api/health" -) - -// Registrator is the concrete type that implements the factory.Registrator and -// healthapi.HealthServer and networkapi.NetworkServiceServer interfaces. -type Registrator struct { - healthapi.UnimplementedHealthServer - - Networkd *networkd.Networkd -} - -// NewRegistrator builds new Registrator instance. -func NewRegistrator(n *networkd.Networkd) (*Registrator, error) { - return &Registrator{ - Networkd: n, - }, nil -} - -// Register implements the factory.Registrator interface. -func (r *Registrator) Register(s *grpc.Server) { - healthapi.RegisterHealthServer(s, r) -} - -// Check implements the Health api and provides visibilty into the state of networkd. -func (r *Registrator) Check(ctx context.Context, in *empty.Empty) (reply *healthapi.HealthCheckResponse, err error) { - reply = &healthapi.HealthCheckResponse{ - Messages: []*healthapi.HealthCheck{ - { - Status: healthapi.HealthCheck_SERVING, - }, - }, - } - - return reply, nil -} - -// Watch implements the Health api and provides visibilty into the state of networkd. -// Ready signifies the daemon (api) is healthy and ready to serve requests. -func (r *Registrator) Watch(in *healthapi.HealthWatchRequest, srv healthapi.Health_WatchServer) (err error) { - if in == nil { - return errors.New("an input interval is required") - } - - var ( - resp *healthapi.HealthCheckResponse - ticker = time.NewTicker(time.Duration(in.IntervalSeconds) * time.Second) - ) - - defer ticker.Stop() - - for { - select { - case <-srv.Context().Done(): - return srv.Context().Err() - case <-ticker.C: - resp, err = r.Check(srv.Context(), &empty.Empty{}) - if err != nil { - return err - } - - if err = srv.Send(resp); err != nil { - return err - } - } - } -} - -// Ready implements the Health api and provides visibility to the state of networkd. -// Ready signifies the initial network configuration ( interfaces, routes, hostname, resolv.conf ) -// settings have been applied. -// Not Ready signifies that the initial network configuration still needs to happen. -func (r *Registrator) Ready(ctx context.Context, in *empty.Empty) (reply *healthapi.ReadyCheckResponse, err error) { - rdy := &healthapi.ReadyCheck{Status: healthapi.ReadyCheck_NOT_READY} - - if r.Networkd.Ready() { - rdy.Status = healthapi.ReadyCheck_READY - } - - reply = &healthapi.ReadyCheckResponse{ - Messages: []*healthapi.ReadyCheck{ - rdy, - }, - } - - return reply, nil -} diff --git a/internal/app/networkd/pkg/reg/reg_test.go b/internal/app/networkd/pkg/reg/reg_test.go deleted file mode 100644 index 8b64e0464..000000000 --- a/internal/app/networkd/pkg/reg/reg_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -//nolint:testpackage -package reg - -import ( - "context" - "fmt" - "io/ioutil" - "log" - "net" - "os" - "testing" - - "github.com/golang/protobuf/ptypes/empty" - "github.com/stretchr/testify/suite" - "google.golang.org/grpc" - - "github.com/talos-systems/talos/internal/app/networkd/pkg/networkd" - "github.com/talos-systems/talos/pkg/grpc/dialer" - "github.com/talos-systems/talos/pkg/grpc/factory" - healthapi "github.com/talos-systems/talos/pkg/machinery/api/health" -) - -type NetworkdSuite struct { - suite.Suite -} - -func TestNetworkdSuite(t *testing.T) { - suite.Run(t, new(NetworkdSuite)) -} - -func (suite *NetworkdSuite) fakeNetworkdRPC() (*networkd.Networkd, *grpc.Server, net.Listener) { - // Create networkd instance - n, err := networkd.New(log.New(os.Stderr, "", log.LstdFlags), nil) - suite.Assert().NoError(err) - - // Create gRPC server - api, err := NewRegistrator(n) - suite.Require().NoError(err) - - server := factory.NewServer(api) - tmpfile, err := ioutil.TempFile("", "networkd") - suite.Assert().NoError(err) - - listener, err := factory.NewListener( - factory.Network("unix"), - factory.SocketPath(tmpfile.Name()), - ) - suite.Assert().NoError(err) - - return n, server, listener -} - -func (suite *NetworkdSuite) TestHealthAPI() { - nwd, server, listener := suite.fakeNetworkdRPC() - - //nolint:errcheck - defer os.Remove(listener.Addr().String()) - - defer server.Stop() - - //nolint:errcheck - go server.Serve(listener) - - conn, err := grpc.Dial( - fmt.Sprintf("%s://%s", "unix", listener.Addr().String()), - grpc.WithInsecure(), - grpc.WithContextDialer(dialer.DialUnix()), - ) - suite.Assert().NoError(err) - - // Verify base state - nClient := healthapi.NewHealthClient(conn) - hcResp, err := nClient.Check(context.Background(), &empty.Empty{}) - suite.Assert().NoError(err) - // Can only check against unknown since its not guaranteed that - // the host the tests will run on will have an arp table populated. - suite.Assert().NotEqual(healthapi.HealthCheck_UNKNOWN, hcResp.Messages[0].Status) - - rResp, err := nClient.Ready(context.Background(), &empty.Empty{}) - suite.Assert().NoError(err) - suite.Assert().Equal(healthapi.ReadyCheck_NOT_READY, rResp.Messages[0].Status) - - // Trigger ready condition - nwd.SetReady() - suite.Assert().NoError(err) - rResp, err = nClient.Ready(context.Background(), &empty.Empty{}) - suite.Assert().NoError(err) - suite.Assert().Equal(healthapi.ReadyCheck_READY, rResp.Messages[0].Status) - - // Test watch - ctx, cancel := context.WithCancel(context.Background()) - stream, err := nClient.Watch(ctx, &healthapi.HealthWatchRequest{IntervalSeconds: 1}) - suite.Require().NoError(err) - - for i := 0; i < 2; i++ { - hcResp, err = stream.Recv() - suite.Assert().NoError(err) - suite.Assert().NotEqual(healthapi.HealthCheck_UNKNOWN, hcResp.Messages[0].Status) - } - - cancel() - - _, err = stream.Recv() - suite.Assert().Error(err) -} diff --git a/internal/app/networkd/pkg/server/server.go b/internal/app/networkd/pkg/server/server.go index 40616140b..43c58e40b 100644 --- a/internal/app/networkd/pkg/server/server.go +++ b/internal/app/networkd/pkg/server/server.go @@ -2,7 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -// Package server implements network API gRPC server. package server import ( diff --git a/internal/app/networkd/pkg/vip/vip.go b/internal/app/networkd/pkg/vip/vip.go deleted file mode 100644 index 449c3265a..000000000 --- a/internal/app/networkd/pkg/vip/vip.go +++ /dev/null @@ -1,197 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package vip - -import ( - "context" - "fmt" - "log" - "net" - "os" - "time" - - "github.com/plunder-app/kube-vip/pkg/vip" - "go.etcd.io/etcd/client/v3/concurrency" - "golang.org/x/sync/errgroup" - - "github.com/talos-systems/talos/internal/pkg/etcd" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -const campaignRetryInterval = time.Second - -// A Controller provides a control interface for Virtual IP addressing. -type Controller interface { - // Start activates the Virtual IP address controller. - Start(ctx context.Context, logger *log.Logger, eg *errgroup.Group) error -} - -type vipController struct { - ip net.IP - iface *net.Interface -} - -// New creates a new Virtual IP controller. -func New(ip, iface string) (Controller, error) { - ipaddr := net.ParseIP(ip) - if ipaddr == nil { - return nil, fmt.Errorf("failed to parse ip %q as an IP address", ip) - } - - netIf, err := net.InterfaceByName(iface) - if err != nil || netIf == nil { - return nil, fmt.Errorf("failed to find interface %s by name: %w", iface, err) - } - - return &vipController{ - ip: ipaddr, - iface: netIf, - }, nil -} - -// Start implements the Controller interface. -func (c *vipController) Start(ctx context.Context, logger *log.Logger, eg *errgroup.Group) error { - netController, err := vip.NewConfig(c.ip.String(), c.iface.Name, false) - if err != nil { - return err - } - - eg.Go(func() error { - c.maintain(ctx, logger, netController) - - return nil - }) - - return nil -} - -func (c *vipController) etcdElectionKey() string { - return fmt.Sprintf("%s:vip:election:%s", constants.EtcdRootTalosKey, c.ip.String()) -} - -func (c *vipController) maintain(ctx context.Context, logger *log.Logger, netController vip.Network) { - for ctx.Err() == nil { - if err := c.campaign(ctx, logger, netController); err != nil { - logger.Printf("campaign failure: %s", err) - - time.Sleep(campaignRetryInterval) - - continue - } - } -} - -//nolint:gocyclo,cyclop -func (c *vipController) campaign(ctx context.Context, logger *log.Logger, netController vip.Network) error { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - hostname, err := os.Hostname() - if err != nil { - return fmt.Errorf("refusing to join election without a hostname") - } - - ec, err := etcd.NewLocalClient() - if err != nil { - return fmt.Errorf("failed to create local etcd client: %w", err) - } - - defer ec.Close() //nolint:errcheck - - sess, err := concurrency.NewSession(ec.Client) - if err != nil { - return fmt.Errorf("failed to create concurrency session: %w", err) - } - defer sess.Close() //nolint:errcheck - - election := concurrency.NewElection(sess, c.etcdElectionKey()) - - node, err := election.Leader(ctx) - if err != nil { - if err != concurrency.ErrElectionNoLeader { - return fmt.Errorf("failed getting current leader: %w", err) - } - } else if string(node.Kvs[0].Value) == hostname { - logger.Printf("vip: resigning from previous election") - - // we are still leader from the previous election, attempt to resign to force new election - resumedElection := concurrency.ResumeElection(sess, c.etcdElectionKey(), string(node.Kvs[0].Key), node.Kvs[0].CreateRevision) - - if err = resumedElection.Resign(ctx); err != nil { - return fmt.Errorf("failed resigning from previous elections: %w", err) - } - } - - campaignErrCh := make(chan error) - - go func() { - campaignErrCh <- election.Campaign(ctx, hostname) - }() - - select { - case err = <-campaignErrCh: - if err != nil { - return fmt.Errorf("failed to conduct campaign: %w", err) - } - case <-sess.Done(): - logger.Printf("vip: session closed") - } - - defer func() { - // use a new context to resign, as `ctx` might be canceled - resignCtx, resignCancel := context.WithTimeout(context.Background(), 10*time.Second) - defer resignCancel() - - election.Resign(resignCtx) //nolint:errcheck - }() - - if err = netController.AddIP(); err != nil { - return fmt.Errorf("failed to add VIP %q to local interface %q: %w", c.ip.String(), c.iface.Name, err) - } - - defer func() { - logger.Printf("vip: removing shared IP %q on interface %q", c.ip.String(), c.iface.Name) - - if err = netController.DeleteIP(); err != nil { - logger.Printf("vip: error removing shared IP: %s", err) - } - }() - - // ARP is only supported for IPv4 - if c.ip.To4() != nil { - // Send gratuitous ARP to announce the change - if err = vip.ARPSendGratuitous(c.ip.String(), c.iface.Name); err != nil { - return fmt.Errorf("failed to send gratuitous ARP after winning election: %w", err) - } - } - - logger.Printf("vip: enabled shared IP %q on interface %q", c.ip.String(), c.iface.Name) - - observe := election.Observe(ctx) - -observeLoop: - for { - select { - case <-sess.Done(): - logger.Printf("vip: session closed") - - break observeLoop - case <-ctx.Done(): - break observeLoop - case resp, ok := <-observe: - if !ok { - break observeLoop - } - - if string(resp.Kvs[0].Value) != hostname { - logger.Printf("vip: detected new leader %q", string(resp.Kvs[0].Value)) - - break observeLoop - } - } - } - - return nil -} diff --git a/pkg/resources/k8s/static_pod_status.go b/pkg/resources/k8s/static_pod_status.go index 8a5d46515..08f81451c 100644 --- a/pkg/resources/k8s/static_pod_status.go +++ b/pkg/resources/k8s/static_pod_status.go @@ -91,6 +91,11 @@ func (r *StaticPodStatus) ResourceDefinition() meta.ResourceDefinitionSpec { } } +// Status gets pod status. +func (r *StaticPodStatus) Status() *v1.PodStatus { + return r.spec.PodStatus +} + // SetStatus sets pod status. func (r *StaticPodStatus) SetStatus(status *v1.PodStatus) { r.spec.PodStatus = status diff --git a/pkg/resources/network/network.go b/pkg/resources/network/network.go index e666e47b3..5f37e6e89 100644 --- a/pkg/resources/network/network.go +++ b/pkg/resources/network/network.go @@ -35,7 +35,7 @@ func RouteID(destination netaddr.IPPrefix, gateway netaddr.IP) string { dst, _ := destination.MarshalText() //nolint:errcheck gw, _ := gateway.MarshalText() //nolint:errcheck - return fmt.Sprintf("%s/%s", string(dst), string(gw)) + return fmt.Sprintf("%s/%s", string(gw), string(dst)) } // OperatorID builds ID (primary key) for the operators. diff --git a/pkg/resources/network/route_spec.go b/pkg/resources/network/route_spec.go index 0f3043467..b90b66857 100644 --- a/pkg/resources/network/route_spec.go +++ b/pkg/resources/network/route_spec.go @@ -27,6 +27,7 @@ type RouteSpec struct { type RouteSpecSpec struct { Family nethelpers.Family `yaml:"family"` Destination netaddr.IPPrefix `yaml:"dst"` + Source netaddr.IPPrefix `yaml:"src"` Gateway netaddr.IP `yaml:"gateway"` OutLinkName string `yaml:"outLinkName,omitempty"` Table nethelpers.RoutingTable `yaml:"table"` @@ -38,6 +39,40 @@ type RouteSpecSpec struct { ConfigLayer ConfigLayer `yaml:"layer"` } +var ( + zero16 = netaddr.MustParseIP("::") + zero4 = netaddr.MustParseIP("0.0.0.0") +) + +// Normalize converts 0.0.0.0 to zero value. +// +//nolint:gocyclo +func (route *RouteSpecSpec) Normalize() { + if route.Destination.Bits == 0 && (route.Destination.IP.Compare(zero4) == 0 || route.Destination.IP.Compare(zero16) == 0) { + // clear destination to be zero value to support "0.0.0.0/0" routes + route.Destination = netaddr.IPPrefix{} + } + + if route.Gateway.Compare(zero4) == 0 || route.Gateway.Compare(zero16) == 0 { + route.Gateway = netaddr.IP{} + } + + if route.Source.Bits == 0 && (route.Source.IP.Compare(zero4) == 0 || route.Source.IP.Compare(zero16) == 0) { + route.Source = netaddr.IPPrefix{} + } + + switch { + case route.Gateway.IsZero(): + route.Scope = nethelpers.ScopeLink + case route.Destination.IP.IsLinkLocalUnicast() || route.Destination.IP.IsLinkLocalMulticast(): + route.Scope = nethelpers.ScopeLink + case route.Destination.IP.IsLoopback(): + route.Scope = nethelpers.ScopeHost + default: + route.Scope = nethelpers.ScopeGlobal + } +} + // NewRouteSpec initializes a RouteSpec resource. func NewRouteSpec(namespace resource.Namespace, id resource.ID) *RouteSpec { r := &RouteSpec{