Skip to content

Commit

Permalink
chore: allow multiple IP's for siderolink-wireguard-advertised-addr
Browse files Browse the repository at this point in the history
… flag

The code is already there: Talos will simply fail to connect and will try again by rotating the IP.
We simply add support for specifying multiple IP's in the `siderolink-wireguard-advertised-addr` flag separated by a comma.

Fixes #495

Signed-off-by: Dmitriy Matrenichev <[email protected]>
  • Loading branch information
DmitriyMV committed Aug 28, 2024
1 parent 3c1defe commit e2f5795
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 20 deletions.
8 changes: 8 additions & 0 deletions hack/release.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,12 @@ a JSON object.
There are two ways to get audit log, and for both you need Admin role:
1. By using the UI: Simply click "Download audit log" in the main menu.
2. Using `omnictl audit-log` command. This command will stream the audit log from the Omni to the local machine stdout.
"""

[notes.allow-multiple-ip]
title = "Allow multiple IP's in `siderolink-wireguard-advertised-addr` flag"
description = """\
The `siderolink-wireguard-advertised-addr` flag now accepts multiple IP addresses separated by commas. This is useful
when you have multiple IPs (IPv4 and IPv6) on the host machine and want to allow Talos nodes to connect to the Omni
using any of them.
"""
5 changes: 4 additions & 1 deletion internal/pkg/siderolink/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"net/netip"
"os"
"strconv"
"strings"
"syscall"
"time"

Expand Down Expand Up @@ -780,8 +781,10 @@ func (manager *Manager) Provision(ctx context.Context, req *pb.ProvisionRequest)
endpoint = spec.VirtualAddrport
}

endpoints := strings.Split(endpoint, ",")

return &pb.ProvisionResponse{
ServerEndpoint: pb.MakeEndpoints(endpoint),
ServerEndpoint: pb.MakeEndpoints(endpoints...),
ServerPublicKey: manager.wgConfig().PublicKey,
NodeAddressPrefix: spec.NodeSubnet,
ServerAddress: manager.wgConfig().ServerAddress,
Expand Down
63 changes: 44 additions & 19 deletions internal/pkg/siderolink/siderolink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"context"
"errors"
"sync"
"sync/atomic"
"testing"
"time"

Expand All @@ -19,11 +18,13 @@ import (
"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/siderolabs/gen/xtesting/must"
"github.com/siderolabs/go-pointer"
"github.com/siderolabs/go-retry/retry"
pb "github.com/siderolabs/siderolink/api/siderolink"
"github.com/siderolabs/siderolink/pkg/wireguard"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
"go.uber.org/zap/zaptest"
Expand Down Expand Up @@ -52,7 +53,10 @@ func (h *fakeWireguardHandler) SetupDevice(wireguard.DeviceConfig) error {
}

func (h *fakeWireguardHandler) Run(ctx context.Context, logger *zap.Logger) error {
unlock := safeLock(&h.loggerMu)
h.loggerMu.Lock()

unlock := sync.OnceFunc(h.loggerMu.Unlock)

defer unlock()

h.logger = logger
Expand Down Expand Up @@ -105,7 +109,7 @@ func (suite *SiderolinkSuite) SetupTest() {

params := sideromanager.Params{
WireguardEndpoint: "127.0.0.1:0",
AdvertisedEndpoint: config.Config.SiderolinkWireguardAdvertisedAddress,
AdvertisedEndpoint: config.Config.SiderolinkWireguardAdvertisedAddress + "," + TestIP,
APIEndpoint: "127.0.0.1:0",
}

Expand Down Expand Up @@ -237,9 +241,41 @@ func (suite *SiderolinkSuite) TestNodes() {
suite.Assert().NoError(err)
suite.Require().True(proto.Equal(resp, reprovision))

resource, err := safe.StateGet[*siderolink.Link](suite.ctx, suite.state, resource.NewMetadata(siderolink.Namespace, siderolink.LinkType, "testnode", resource.VersionUndefined))
res, err := safe.StateGet[*siderolink.Link](suite.ctx, suite.state, resource.NewMetadata(siderolink.Namespace, siderolink.LinkType, "testnode", resource.VersionUndefined))
suite.Assert().NoError(err)
suite.Require().Equal(privateKey.PublicKey().String(), resource.TypedSpec().Value.NodePublicKey)
suite.Require().Equal(privateKey.PublicKey().String(), res.TypedSpec().Value.NodePublicKey)
}

func (suite *SiderolinkSuite) TestNodeWithSeveralAdvertisedIPs() {
var spec *specs.ConnectionParamsSpec

ctx, cancel := context.WithTimeout(suite.ctx, time.Second*2)
defer cancel()

rtestutils.AssertResources[*siderolink.ConnectionParams](ctx, suite.T(), suite.state, []string{
siderolink.ConfigID,
}, func(r *siderolink.ConnectionParams, assertion *assert.Assertions) {
assertion.NotEmpty(r.TypedSpec().Value.Args)
assertion.NotEmpty(r.TypedSpec().Value.ApiEndpoint)
assertion.NotEmpty(r.TypedSpec().Value.JoinToken)
assertion.NotEmpty(r.TypedSpec().Value.WireguardEndpoint)

spec = r.TypedSpec().Value
})

conn := must.Value(grpc.NewClient(suite.address, grpc.WithTransportCredentials(insecure.NewCredentials())))(suite.T())
client := pb.NewProvisionServiceClient(conn)
privateKey := must.Value(wgtypes.GeneratePrivateKey())(suite.T())
resp := must.Value(client.Provision(
suite.ctx,
&pb.ProvisionRequest{
NodeUuid: "testnode",
NodePublicKey: privateKey.PublicKey().String(),
JoinToken: &spec.JoinToken,
},
))(suite.T())

require.Equal(suite.T(), []string{config.Config.SiderolinkWireguardAdvertisedAddress, TestIP}, resp.GetEndpoints())
}

func (suite *SiderolinkSuite) TestVirtualNodes() {
Expand Down Expand Up @@ -317,7 +353,7 @@ func (suite *SiderolinkSuite) TestVirtualNodes() {

expectedResp := resp.CloneVT()
expectedResp.GrpcPeerAddrPort = ""
expectedResp.ServerEndpoint = pb.MakeEndpoints(config.Config.SiderolinkWireguardAdvertisedAddress)
expectedResp.ServerEndpoint = pb.MakeEndpoints(config.Config.SiderolinkWireguardAdvertisedAddress, TestIP)

suite.Assert().NoError(err)

Expand Down Expand Up @@ -384,16 +420,5 @@ func TestSiderolinkSuite(t *testing.T) {
suite.Run(t, new(SiderolinkSuite))
}

func safeLock(mx sync.Locker) func() {
mx.Lock()

var locked atomic.Bool

locked.Store(true)

return func() {
if locked.Swap(false) {
mx.Unlock()
}
}
}
// TestIP from TEST-NET-1 network which can never be used.
const TestIP = "192.2.0.2"

0 comments on commit e2f5795

Please sign in to comment.