chore: use "handle-like" resource in DNSResolveCacheController

Rework (and simplify) `DNSResolveCacheController` to use `DNSUpstream` "handle-like" resources.

Depends on https://github.com/cosi-project/runtime/pull/400

Signed-off-by: Dmitriy Matrenichev <dmitry.matrenichev@siderolabs.com>
This commit is contained in:
Dmitriy Matrenichev 2024-02-05 17:03:20 +03:00
parent 013e130702
commit afa71d6b02
No known key found for this signature in database
GPG Key ID: D3363CF894E68892
24 changed files with 991 additions and 1029 deletions

Binary file not shown.

View File

@ -93,7 +93,6 @@ message DHCP6OperatorSpec {
// DNSResolveCacheSpec describes DNS servers status.
message DNSResolveCacheSpec {
string status = 1;
repeated common.NetIP servers = 2;
}
// HardwareAddrSpec describes spec for the link.

4
go.mod
View File

@ -47,7 +47,7 @@ require (
github.com/containernetworking/plugins v1.4.0
github.com/coredns/coredns v1.11.1
github.com/coreos/go-iptables v0.7.0
github.com/cosi-project/runtime v0.3.20
github.com/cosi-project/runtime v0.4.0-alpha.4
github.com/distribution/reference v0.5.0
github.com/docker/docker v25.0.2+incompatible
github.com/docker/go-connections v0.5.0
@ -235,7 +235,7 @@ require (
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gosuri/uilive v0.0.4 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect

8
go.sum
View File

@ -184,8 +184,8 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cosi-project/runtime v0.3.20 h1:pl8mwbHMFIRFYV8v0Glxw2ruhTXn/5ij7TSlO9nApi4=
github.com/cosi-project/runtime v0.3.20/go.mod h1:3DQsIr7zF/bmWfHOnpHmOQ9mDukFGi8AMoHx2rNsi+s=
github.com/cosi-project/runtime v0.4.0-alpha.4 h1:3TN+Y0NVKa/1QXqR3QTJ6ceWrcflyUeIZbQnrU2BprM=
github.com/cosi-project/runtime v0.4.0-alpha.4/go.mod h1:JE9yuyufGRCd28AyCWFkTNf3UMiZJT722bpfPEPnsNE=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@ -397,8 +397,8 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWet
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=

View File

@ -6,8 +6,6 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0 h1:QfV5XZt6iNa2aWMAt96CZEbfJ7kgG/qYIpq465Shr5E=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.4.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0 h1:MxA59PGoCFb+vCwRQi3PhQEwHj4+r2dhuv9HG+vM7iM=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.5.0/go.mod h1:uYt4CfhkJA9o0FN7jfE5minm/i4nUE4MjGUJkzB6Zs8=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
@ -47,8 +45,6 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/aws/aws-sdk-go v1.50.5 h1:H2Aadcgwr7a2aqS6ZwcE+l1mA6ZrTseYCvjw2QLmxIA=
github.com/aws/aws-sdk-go v1.50.5/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.50.8 h1:gY0WoOW+/Wz6XmYSgDH9ge3wnAevYDSQWPxxJvqAkP4=
github.com/aws/aws-sdk-go v1.50.8/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=

View File

@ -44,6 +44,10 @@ func (s *InspectServer) ControllerRuntimeDependencies(ctx context.Context, in *e
edgeType = inspectapi.DependencyEdgeType_INPUT_WEAK
case controller.EdgeInputDestroyReady:
edgeType = inspectapi.DependencyEdgeType_INPUT_DESTROY_READY
case controller.EdgeInputQPrimary,
controller.EdgeInputQMapped,
controller.EdgeInputQMappedDestroyReady:
return nil, fmt.Errorf("unexpected edge type: %v", graph.Edges[i].EdgeType)
}
edges = append(edges, &inspectapi.ControllerDependencyEdge{

View File

@ -9,16 +9,15 @@ import (
"fmt"
"time"
"github.com/coredns/coredns/plugin/pkg/proxy"
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/cosi-project/runtime/pkg/state"
"github.com/siderolabs/gen/optional"
"go.uber.org/zap"
"github.com/siderolabs/talos/internal/pkg/ctxutil"
"github.com/siderolabs/talos/internal/pkg/dns"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
"github.com/siderolabs/talos/pkg/machinery/resources/network"
)
@ -36,18 +35,7 @@ func (ctrl *DNSResolveCacheController) Name() string {
// Inputs implements controller.Controller interface.
func (ctrl *DNSResolveCacheController) Inputs() []controller.Input {
return []controller.Input{
{
Namespace: network.NamespaceName,
Type: network.ResolverStatusType,
ID: optional.Some(network.ResolverID),
Kind: controller.InputWeak,
},
{
Namespace: config.NamespaceName,
Type: config.MachineConfigType,
ID: optional.Some(config.V1Alpha1ID),
Kind: controller.InputWeak,
},
safe.Input[*network.DNSUpstream](controller.InputWeak),
}
}
@ -70,22 +58,18 @@ func (ctrl *DNSResolveCacheController) Run(ctx context.Context, r controller.Run
case <-r.EventCh():
}
mc, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
upstreams, err := safe.ReaderListAll[*network.DNSUpstream](ctx, r)
if err != nil {
if state.IsNotFoundError(err) {
continue
}
return err
return fmt.Errorf("error getting resolver status: %w", err)
}
if !mc.Config().Machine().Features().LocalDNSEnabled() {
if upstreams.Len() == 0 {
continue
}
err = func() error {
ctrl.Logger.Info("starting dns cache resolve")
defer ctrl.Logger.Info("stopping dns cache resolve")
ctrl.Logger.Info("starting dns caching resolver")
defer ctrl.Logger.Info("stopping dns caching resolver")
return ctrl.runServer(ctx, r)
}()
@ -95,10 +79,9 @@ func (ctrl *DNSResolveCacheController) Run(ctx context.Context, r controller.Run
}
}
func (ctrl *DNSResolveCacheController) writeDNSStatus(ctx context.Context, r controller.Runtime, net resource.ID, handler *dns.Handler) error {
func (ctrl *DNSResolveCacheController) writeDNSStatus(ctx context.Context, r controller.Runtime, net resource.ID) error {
return safe.WriterModify(ctx, r, network.NewDNSResolveCache(net), func(drc *network.DNSResolveCache) error {
drc.TypedSpec().Status = "running"
drc.TypedSpec().Servers = handler.ProxyList()
return nil
})
@ -140,7 +123,7 @@ func (ctrl *DNSResolveCacheController) runServer(originCtx context.Context, r co
runner := dns.NewRunner(dns.NewServer(opt), l)
err := ctrl.writeDNSStatus(ctx, r, opt.Net, handler)
err := ctrl.writeDNSStatus(ctx, r, opt.Net)
if err != nil {
return err
}
@ -164,33 +147,31 @@ func (ctrl *DNSResolveCacheController) runServer(originCtx context.Context, r co
eventCh = r.EventCh()
mc, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
upstreams, err := safe.ReaderListAll[*network.DNSUpstream](ctx, r)
if err != nil {
return err
}
if !mc.Config().Machine().Features().LocalDNSEnabled() {
return nil
}
resolverStatus, err := safe.ReaderGetByID[*network.ResolverStatus](ctx, r, network.ResolverID)
if err != nil {
if state.IsNotFoundError(err) {
continue
}
return fmt.Errorf("error getting resolver status: %w", err)
}
ctrl.Logger.Info("updating dns server nameservers", zap.Stringers("data", resolverStatus.TypedSpec().DNSServers))
if upstreams.Len() == 0 {
return nil
}
err = handler.SetProxy(resolverStatus.TypedSpec().DNSServers)
if err != nil {
return fmt.Errorf("error setting dns server nameservers: %w", err)
addrs := make([]string, 0, upstreams.Len())
prxs := make([]*proxy.Proxy, 0, len(addrs))
for it := upstreams.Iterator(); it.Next(); {
upstream := it.Value()
addrs = append(addrs, upstream.TypedSpec().Value.Prx.Addr())
prxs = append(prxs, upstream.TypedSpec().Value.Prx.(*proxy.Proxy)) //nolint:forcetypeassert
}
if handler.SetProxy(prxs) {
ctrl.Logger.Info("updated dns server nameservers", zap.Strings("addrs", addrs))
}
for _, n := range []string{"udp", "tcp"} {
err = ctrl.writeDNSStatus(ctx, r, n, handler)
err = ctrl.writeDNSStatus(ctx, r, n)
if err != nil {
return err
}

View File

@ -56,9 +56,10 @@ func (suite *DNSServer) TestResolving() {
rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{"tcp", "udp"}, func(r *network.DNSResolveCache, assert *assert.Assertions) {
assert.Equal("running", r.TypedSpec().Status)
assert.Equal(dnsSlice, xslices.Map(r.TypedSpec().Servers, netip.Addr.String))
})
rtestutils.AssertLength[*network.DNSUpstream](suite.Ctx(), suite.T(), suite.State(), len(dnsSlice))
msg := &dns.Msg{
MsgHdr: dns.MsgHdr{
Id: dns.Id(),
@ -111,9 +112,9 @@ func (suite *DNSServer) TestSetupStartStop() {
rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{"tcp", "udp"}, func(r *network.DNSResolveCache, assert *assert.Assertions) {
assert.Equal("running", r.TypedSpec().Status)
assert.Equal(dnsSlice, xslices.Map(r.TypedSpec().Servers, netip.Addr.String))
})
rtestutils.AssertLength[*network.DNSUpstream](suite.Ctx(), suite.T(), suite.State(), len(dnsSlice))
// stop dns resolver
cfg.Container().RawV1Alpha1().MachineConfig.MachineFeatures.LocalDNS = pointer.To(false)
@ -123,6 +124,10 @@ func (suite *DNSServer) TestSetupStartStop() {
ctest.AssertNoResource[*network.DNSResolveCache](suite, "tcp")
ctest.AssertNoResource[*network.DNSResolveCache](suite, "udp")
for _, d := range dnsSlice {
ctest.AssertNoResource[*network.DNSUpstream](suite, d)
}
// start dns resolver again
cfg.Container().RawV1Alpha1().MachineConfig.MachineFeatures.LocalDNS = pointer.To(true)
@ -131,8 +136,9 @@ func (suite *DNSServer) TestSetupStartStop() {
rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{"tcp", "udp"}, func(r *network.DNSResolveCache, assert *assert.Assertions) {
assert.Equal("running", r.TypedSpec().Status)
assert.Equal(dnsSlice, xslices.Map(r.TypedSpec().Servers, netip.Addr.String))
})
rtestutils.AssertLength[*network.DNSUpstream](suite.Ctx(), suite.T(), suite.State(), len(dnsSlice))
}
func TestDNSServer(t *testing.T) {
@ -140,6 +146,7 @@ func TestDNSServer(t *testing.T) {
DefaultSuite: ctest.DefaultSuite{
Timeout: 10 * time.Second,
AfterSetup: func(suite *ctest.DefaultSuite) {
suite.Require().NoError(suite.Runtime().RegisterController(&netctrl.DNSUpstreamController{}))
suite.Require().NoError(suite.Runtime().RegisterController(&netctrl.DNSResolveCacheController{
Addr: ":10700",
Logger: zaptest.NewLogger(t),

View File

@ -0,0 +1,162 @@
// 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 network
import (
"context"
"net"
"time"
"github.com/coredns/coredns/plugin/pkg/proxy"
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/cosi-project/runtime/pkg/state"
"github.com/siderolabs/gen/optional"
"go.uber.org/zap"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
"github.com/siderolabs/talos/pkg/machinery/resources/network"
)
// DNSUpstreamController is a controller that manages DNS upstreams.
type DNSUpstreamController struct{}
// Name implements controller.Controller interface.
func (ctrl *DNSUpstreamController) Name() string {
return "network.DNSUpstreamController"
}
// Inputs implements controller.Controller interface.
func (ctrl *DNSUpstreamController) Inputs() []controller.Input {
return []controller.Input{
{
Namespace: config.NamespaceName,
Type: config.MachineConfigType,
ID: optional.Some(config.V1Alpha1ID),
Kind: controller.InputWeak,
},
{
Namespace: network.NamespaceName,
Type: network.ResolverStatusType,
ID: optional.Some(network.ResolverID),
Kind: controller.InputWeak,
},
}
}
// Outputs implements controller.Controller interface.
func (ctrl *DNSUpstreamController) Outputs() []controller.Output {
return []controller.Output{
{
Type: network.DNSUpstreamType,
Kind: controller.OutputExclusive,
},
}
}
// Run implements controller.Controller interface.
func (ctrl *DNSUpstreamController) Run(ctx context.Context, r controller.Runtime, l *zap.Logger) error {
defer ctrl.cleanupUpstream(context.Background(), r, nil, l)
for {
select {
case <-ctx.Done():
return nil
case <-r.EventCh():
}
if err := ctrl.run(ctx, r, l); err != nil {
return err
}
r.ResetRestartBackoff()
}
}
func (ctrl *DNSUpstreamController) run(ctx context.Context, r controller.Runtime, l *zap.Logger) error {
touchedIDs := map[resource.ID]struct{}{}
defer ctrl.cleanupUpstream(ctx, r, touchedIDs, l)
mc, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
if err != nil {
if state.IsNotFoundError(err) {
return nil
}
return err
}
if !mc.Config().Machine().Features().LocalDNSEnabled() {
return nil
}
rs, err := safe.ReaderGetByID[*network.ResolverStatus](ctx, r, network.ResolverID)
if err != nil {
if state.IsNotFoundError(err) {
return nil
}
return err
}
for _, s := range rs.TypedSpec().DNSServers {
remoteAddr := s.String()
if err = safe.WriterModify[*network.DNSUpstream](
ctx,
r,
network.NewDNSUpstream(remoteAddr),
func(u *network.DNSUpstream) error {
touchedIDs[u.Metadata().ID()] = struct{}{}
if u.TypedSpec().Value.Prx != nil {
return nil
}
prx := proxy.NewProxy(remoteAddr, net.JoinHostPort(remoteAddr, "53"), "dns")
prx.Start(500 * time.Millisecond)
u.TypedSpec().Value.Prx = prx
l.Info("created dns upstream", zap.String("addr", remoteAddr))
return nil
},
); err != nil {
return err
}
}
return nil
}
func (ctrl *DNSUpstreamController) cleanupUpstream(ctx context.Context, r controller.Runtime, touchedIDs map[resource.ID]struct{}, l *zap.Logger) {
list, err := safe.ReaderListAll[*network.DNSUpstream](ctx, r)
if err != nil {
l.Error("error listing upstreams", zap.Error(err))
return
}
for it := list.Iterator(); it.Next(); {
val := it.Value()
md := val.Metadata()
if _, ok := touchedIDs[md.ID()]; !ok {
val.TypedSpec().Value.Prx.Stop()
if err = r.Destroy(ctx, md); err != nil {
l.Error("error destroying upstream", zap.Error(err), zap.String("id", md.ID()))
return
}
l.Info("destroyed dns upstream", zap.String("addr", md.ID()))
}
}
}

View File

@ -1359,8 +1359,7 @@ func LeaveEtcd(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {
continue
}
//nolint:exhaustive
switch service.GetState() {
switch service.GetState() { //nolint:exhaustive
case events.StateRunning:
fallthrough
case events.StateStopping:

View File

@ -192,6 +192,7 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
Addr: "127.0.0.1:53",
Logger: dnsCacheLogger,
},
&network.DNSUpstreamController{},
&network.EtcFileController{
PodResolvConfPath: constants.PodResolvConfPath,
},

View File

@ -149,6 +149,7 @@ func NewState() (*State, error) {
&network.AddressSpec{},
&network.DeviceConfigSpec{},
&network.DNSResolveCache{},
&network.DNSUpstream{},
&network.HardwareAddr{},
&network.HostnameStatus{},
&network.HostnameSpec{},

View File

@ -9,8 +9,7 @@ import (
"context"
"errors"
"math/rand"
"net"
"net/netip"
"slices"
"strings"
"sync"
"time"
@ -20,8 +19,6 @@ import (
"github.com/coredns/coredns/plugin/pkg/proxy"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
"github.com/siderolabs/gen/pair"
"github.com/siderolabs/gen/xslices"
"go.uber.org/zap"
"github.com/siderolabs/talos/internal/pkg/utils"
@ -96,7 +93,7 @@ func (c *Cache) ServeDNS(wr dns.ResponseWriter, msg *dns.Msg) {
// Handler is a dns proxy selector.
type Handler struct {
mx sync.RWMutex
dests []pair.Pair[netip.Addr, *proxy.Proxy]
dests []*proxy.Proxy
logger *zap.Logger
}
@ -121,7 +118,7 @@ func (h *Handler) ServeDNS(ctx context.Context, wrt dns.ResponseWriter, msg *dns
h.logger.Debug("dns request", zap.Stringer("data", msg))
upstreams := xslices.Map(h.dests, func(h pair.Pair[netip.Addr, *proxy.Proxy]) *proxy.Proxy { return h.F2 })
upstreams := slices.Clone(h.dests)
if len(upstreams) == 0 {
emptyProxyErr := new(dns.Msg).SetRcode(req.Req, dns.RcodeServerFailure)
@ -185,43 +182,21 @@ func (h *Handler) ServeDNS(ctx context.Context, wrt dns.ResponseWriter, msg *dns
}
// SetProxy sets destination dns proxy servers.
func (h *Handler) SetProxy(servers []netip.Addr) error {
func (h *Handler) SetProxy(prxs []*proxy.Proxy) bool {
h.mx.Lock()
defer h.mx.Unlock()
var err error
if slices.Equal(h.dests, prxs) {
return false
}
h.dests, err = utils.UpdatePairSet(h.dests, servers, onAdd, onRemove)
h.dests = prxs
return err
}
func onAdd(addr netip.Addr) (*proxy.Proxy, error) {
dst := addr.String()
result := proxy.NewProxy(dst, net.JoinHostPort(dst, "53"), "dns")
result.Start(500 * time.Millisecond)
return result, nil
}
func onRemove(h pair.Pair[netip.Addr, *proxy.Proxy]) error {
h.F2.Stop()
return nil
return true
}
// Stop stops and clears dns proxy selector.
func (h *Handler) Stop() { h.SetProxy(nil) } //nolint:errcheck
// ProxyList returns a list of destination dns proxy servers.
func (h *Handler) ProxyList() []netip.Addr {
h.mx.RLock()
defer h.mx.RUnlock()
return xslices.Map(h.dests, func(h pair.Pair[netip.Addr, *proxy.Proxy]) netip.Addr { return h.F1 })
}
func (h *Handler) Stop() { h.SetProxy(nil) }
// ServerOptins is a Server options.
type ServerOptins struct {

View File

@ -7,12 +7,13 @@ package dns_test
import (
"context"
"errors"
"net/netip"
"net"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/coredns/coredns/plugin/pkg/proxy"
dnssrv "github.com/miekg/dns"
"github.com/siderolabs/gen/xslices"
"github.com/siderolabs/gen/xtesting/check"
@ -105,12 +106,18 @@ func newServer(t *testing.T, nameservers ...string) (context.Context, func()) {
handler := dns.NewHandler(l)
t.Cleanup(handler.Stop)
pxy := xslices.Map(nameservers, netip.MustParseAddr)
pxs := xslices.Map(nameservers, func(ns string) *proxy.Proxy {
p := proxy.NewProxy(ns, net.JoinHostPort(ns, "53"), "dns")
p.Start(500 * time.Millisecond)
err := handler.SetProxy(pxy)
require.NoError(t, err)
t.Cleanup(func() {
p.Stop()
})
require.Equal(t, pxy, handler.ProxyList())
return p
})
handler.SetProxy(pxs)
runner := dns.NewRunner(dns.NewServer(dns.ServerOptins{
Addr: ":10700",

View File

@ -7,58 +7,9 @@ package utils
import (
"errors"
"slices"
"sync/atomic"
"github.com/siderolabs/gen/pair"
)
// UpdatePairSet updates a set of pairs. It removes pairs that are not in toAdd and adds pairs that are not in old.
func UpdatePairSet[T comparable, H any](
old []pair.Pair[T, H],
toAdd []T,
add func(T) (H, error),
remove func(pair.Pair[T, H]) error,
) ([]pair.Pair[T, H], error) {
var err error
result := slices.DeleteFunc(old, func(h pair.Pair[T, H]) bool {
if err != nil {
return false
}
if slices.Contains(toAdd, h.F1) {
return false
}
err = remove(h)
if err != nil { //nolint:gosimple
return false
}
return true
})
if err != nil {
return result, err
}
for _, val := range toAdd {
if slices.ContainsFunc(old, func(h pair.Pair[T, H]) bool { return h.F1 == val }) {
continue
}
h, err := add(val)
if err != nil {
return result, err
}
result = append(result, pair.MakePair(val, h))
}
return result, nil
}
const (
notRunning = iota
running

View File

@ -1,118 +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 utils_test
import (
"errors"
"strconv"
"testing"
"github.com/siderolabs/gen/pair"
"github.com/siderolabs/gen/xslices"
"github.com/siderolabs/gen/xtesting/check"
"github.com/stretchr/testify/require"
"github.com/siderolabs/talos/internal/pkg/utils"
)
func TestHandleSet(t *testing.T) {
table := []struct {
state string
vals []int
expected []string
removed []string
expectedErr check.Check
}{
{
"initial state",
[]int{1, 2, 3},
[]string{"1", "2", "3"},
nil,
check.NoError(),
},
{
"add and remove",
[]int{1, 2, 4},
[]string{"1", "2", "4"},
[]string{"3"},
check.NoError(),
},
{
"add and remove with error",
[]int{1, 2, 5, 42, 43},
[]string{"1", "2", "5"},
[]string{"4"},
check.EqualError("42 is not allowed"),
},
{
"remove all",
[]int{},
nil,
[]string{"1", "2", "5"},
check.NoError(),
},
{
"start again",
[]int{1, 2, 3, 45, 46},
[]string{"1", "2", "3", "45", "46"},
nil,
check.NoError(),
},
{
"remove with error",
[]int{2, 3},
[]string{"2", "3", "45", "46"},
[]string{"1"},
check.EqualError("45 is not allowed to delete"),
},
{
"remove all again",
[]int{},
nil,
[]string{"2", "3", "45", "46"},
check.NoError(),
},
}
oneWithError := false
add := func(i int) (string, error) {
if i == 42 {
return "", errors.New("42 is not allowed")
}
return strconv.Itoa(i), nil
}
var removed []string
remove := func(h pair.Pair[int, string]) error {
if h.F1 == 45 && !oneWithError {
oneWithError = true
return errors.New("45 is not allowed to delete")
}
removed = append(removed, h.F2)
return nil
}
var hs []pair.Pair[int, string]
for _, tt := range table {
t.Run(tt.state, func(t *testing.T) {
removed = nil
var err error
hs, err = utils.UpdatePairSet(hs, tt.vals, add, remove)
tt.expectedErr(t, err)
require.Equal(t, tt.expected, xslices.Map(hs, func(h pair.Pair[int, string]) string { return h.F2 }))
require.Equal(t, tt.removed, removed)
})
}
}

File diff suppressed because it is too large Load Diff

View File

@ -729,30 +729,6 @@ func (m *DNSResolveCacheSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.Servers) > 0 {
for iNdEx := len(m.Servers) - 1; iNdEx >= 0; iNdEx-- {
if vtmsg, ok := interface{}(m.Servers[iNdEx]).(interface {
MarshalToSizedBufferVT([]byte) (int, error)
}); ok {
size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarint(dAtA, i, uint64(size))
} else {
encoded, err := proto.Marshal(m.Servers[iNdEx])
if err != nil {
return 0, err
}
i -= len(encoded)
copy(dAtA[i:], encoded)
i = encodeVarint(dAtA, i, uint64(len(encoded)))
}
i--
dAtA[i] = 0x12
}
}
if len(m.Status) > 0 {
i -= len(m.Status)
copy(dAtA[i:], m.Status)
@ -3786,18 +3762,6 @@ func (m *DNSResolveCacheSpec) SizeVT() (n int) {
if l > 0 {
n += 1 + l + sov(uint64(l))
}
if len(m.Servers) > 0 {
for _, e := range m.Servers {
if size, ok := interface{}(e).(interface {
SizeVT() int
}); ok {
l = size.SizeVT()
} else {
l = proto.Size(e)
}
n += 1 + l + sov(uint64(l))
}
}
n += len(m.unknownFields)
return n
}
@ -6508,48 +6472,6 @@ func (m *DNSResolveCacheSpec) UnmarshalVT(dAtA []byte) error {
}
m.Status = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Servers", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Servers = append(m.Servers, &common.NetIP{})
if unmarshal, ok := interface{}(m.Servers[len(m.Servers)-1]).(interface {
UnmarshalVT([]byte) error
}); ok {
if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
return err
}
} else {
if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Servers[len(m.Servers)-1]); err != nil {
return err
}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skip(dAtA[iNdEx:])

View File

@ -9,7 +9,7 @@ replace gopkg.in/yaml.v3 => github.com/unix4ever/yaml v0.0.0-20220527175918-f17b
require (
github.com/blang/semver/v4 v4.0.0
github.com/containerd/go-cni v1.1.9
github.com/cosi-project/runtime v0.3.20
github.com/cosi-project/runtime v0.4.0-alpha.4
github.com/dustin/go-humanize v1.0.1
github.com/evanphx/json-patch v5.9.0+incompatible
github.com/ghodss/yaml v1.0.0
@ -43,25 +43,27 @@ require (
github.com/gertd/go-pluralize v0.2.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect
github.com/google/pprof v0.0.0-20230509042627-b1315fad0c5a // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/mdlayher/genetlink v1.3.2 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
github.com/onsi/gomega v1.20.1 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
github.com/onsi/gomega v1.27.8 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

View File

@ -22,8 +22,8 @@ github.com/containerd/go-cni v1.1.9 h1:ORi7P1dYzCwVM6XPN4n3CbkuOx/NZ2DOqy+SHRdo9
github.com/containerd/go-cni v1.1.9/go.mod h1:XYrZJ1d5W6E2VOvjffL3IZq0Dz6bsVlERHbekNK90PM=
github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ=
github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
github.com/cosi-project/runtime v0.3.20 h1:pl8mwbHMFIRFYV8v0Glxw2ruhTXn/5ij7TSlO9nApi4=
github.com/cosi-project/runtime v0.3.20/go.mod h1:3DQsIr7zF/bmWfHOnpHmOQ9mDukFGi8AMoHx2rNsi+s=
github.com/cosi-project/runtime v0.4.0-alpha.4 h1:3TN+Y0NVKa/1QXqR3QTJ6ceWrcflyUeIZbQnrU2BprM=
github.com/cosi-project/runtime v0.4.0-alpha.4/go.mod h1:JE9yuyufGRCd28AyCWFkTNf3UMiZJT722bpfPEPnsNE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -37,7 +37,11 @@ github.com/gertd/go-pluralize v0.2.1 h1:M3uASbVjMnTsPb0PNqg+E/24Vwigyo/tvyMTtAlL
github.com/gertd/go-pluralize v0.2.1/go.mod h1:rbYaKDbsXxmRfr8uygAEKhOWsjyrrqrkHVpZvoOp8zk=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@ -56,8 +60,10 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y=
github.com/google/pprof v0.0.0-20230509042627-b1315fad0c5a h1:PEOGDI1kkyW37YqPWHLHc+D20D9+87Wt12TCcfTUo5Q=
github.com/google/pprof v0.0.0-20230509042627-b1315fad0c5a/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@ -87,13 +93,13 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
@ -147,8 +153,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI=
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@ -165,15 +171,15 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -211,11 +217,15 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -27,10 +27,6 @@ func (o AddressStatusSpec) DeepCopy() AddressStatusSpec {
// DeepCopy generates a deep copy of DNSResolveCacheSpec.
func (o DNSResolveCacheSpec) DeepCopy() DNSResolveCacheSpec {
var cp DNSResolveCacheSpec = o
if o.Servers != nil {
cp.Servers = make([]netip.Addr, len(o.Servers))
copy(cp.Servers, o.Servers)
}
return cp
}

View File

@ -5,8 +5,6 @@
package network
import (
"net/netip"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/resource/meta"
"github.com/cosi-project/runtime/pkg/resource/protobuf"
@ -25,8 +23,7 @@ type DNSResolveCache = typed.Resource[DNSResolveCacheSpec, DNSResolveCacheExtens
//
//gotagsrewrite:gen
type DNSResolveCacheSpec struct {
Status string `yaml:"status" protobuf:"1"`
Servers []netip.Addr `yaml:"servers" protobuf:"2"`
Status string `yaml:"status" protobuf:"1"`
}
// NewDNSResolveCache initializes a DNSResolveCache resource.

View File

@ -0,0 +1,82 @@
// 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 network
import (
"strconv"
"time"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/resource/handle"
"github.com/cosi-project/runtime/pkg/resource/meta"
"github.com/cosi-project/runtime/pkg/resource/typed"
)
// DNSUpstreamType is type of DNSUpstream resource.
const DNSUpstreamType = resource.Type("DNSUpstreams.net.talos.dev")
// DNSUpstream resource holds DNS resolver info.
type DNSUpstream = typed.Resource[DNSUpstreamSpec, DNSUpstreamExtension]
// DNSUpstreamSpec describes DNS upstreams status.
type DNSUpstreamSpec = handle.ResourceSpec[*DNSUpstreamSpecSpec]
// DNSUpstreamSpecSpec describes DNS upstreams status.
type DNSUpstreamSpecSpec struct {
// Proxy is essentially a *proxy.Proxy interface. It's here because we don't want machinery to depend on coredns.
// We could use a generic struct here, but without generic aliases the usage would look ugly.
// Once generic aliases are here, redo the type above as `type DNSUpstream[P Proxy] = typed.Resource[...]`.
Prx Proxy
}
// MarshalYAML implements yaml.Marshaler interface.
func (d *DNSUpstreamSpecSpec) MarshalYAML() (interface{}, error) {
d.Prx.Healthcheck()
return map[string]string{
"healthy": strconv.FormatBool(d.Prx.Fails() == 0),
"addr": d.Prx.Addr(),
}, nil
}
// NewDNSUpstream initializes a DNSUpstream resource.
func NewDNSUpstream(id resource.ID) *DNSUpstream {
return typed.NewResource[DNSUpstreamSpec, DNSUpstreamExtension](
resource.NewMetadata(NamespaceName, DNSUpstreamType, id, resource.VersionUndefined),
DNSUpstreamSpec{Value: &DNSUpstreamSpecSpec{}},
)
}
// DNSUpstreamExtension provides auxiliary methods for DNSUpstream.
type DNSUpstreamExtension struct{}
// ResourceDefinition implements [typed.Extension] interface.
func (DNSUpstreamExtension) ResourceDefinition() meta.ResourceDefinitionSpec {
return meta.ResourceDefinitionSpec{
Type: DNSUpstreamType,
Aliases: []resource.Type{},
DefaultNamespace: NamespaceName,
PrintColumns: []meta.PrintColumn{
{
Name: "Healthy",
JSONPath: "{.healthy}",
},
{
Name: "Address",
JSONPath: "{.addr}",
},
},
}
}
// Proxy is essentially a proxy.Proxy interface. It's here because we don't want machinery to depend on coredns.
// The good thing we don't need any additional methods from coredns, so we can use a simple interface.
type Proxy interface {
Addr() string
Fails() uint32
Healthcheck()
Stop()
Start(duration time.Duration)
}

View File

@ -2911,7 +2911,6 @@ DNSResolveCacheSpec describes DNS servers status.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| status | [string](#string) | | |
| servers | [common.NetIP](#common.NetIP) | repeated | |