sidero/app/sidero-controller-manager/internal/siderolink/server.go
Andrey Smirnov fbcd02a45d
feat: update for Talos 1.3.0
Rename to siderolabs, bump dependencies, controller-runtime, get rid of
netaddr, new SideroLink API, etc.

Use bootstrap cluster with a control plane + worker to avoid nasty
restarts when host-mode SideroLink IP pops up.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
2022-12-16 16:35:30 +04:00

103 lines
2.7 KiB
Go

// 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 siderolink
import (
"context"
"crypto/rand"
"fmt"
"io"
"net/netip"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/cluster-api/util/patch"
runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
pb "github.com/siderolabs/siderolink/api/siderolink"
sidero "github.com/siderolabs/sidero/app/caps-controller-manager/api/v1alpha3"
)
// Server implements gRPC API.
type Server struct {
pb.UnimplementedProvisionServiceServer
cfg *Config
metalClient runtimeclient.Client
}
// NewServer initializes new server.
func NewServer(cfg *Config, metalClient runtimeclient.Client) *Server {
return &Server{
cfg: cfg,
metalClient: metalClient,
}
}
// Provision the SideroLink for the server by UUID.
func (srv *Server) Provision(ctx context.Context, req *pb.ProvisionRequest) (*pb.ProvisionResponse, error) {
var serverbinding sidero.ServerBinding
if err := srv.metalClient.Get(ctx, types.NamespacedName{Name: req.NodeUuid}, &serverbinding); err != nil {
if apierrors.IsNotFound(err) {
return nil, status.Error(codes.NotFound, fmt.Sprintf("server binding %q not found", req.NodeUuid))
}
return nil, err
}
patchHelper, err := patch.NewHelper(&serverbinding, srv.metalClient)
if err != nil {
return nil, err
}
var nodeAddress netip.Prefix
if serverbinding.Spec.SideroLink.NodeAddress != "" {
// find already provisioned address
nodeAddress, err = netip.ParsePrefix(serverbinding.Spec.SideroLink.NodeAddress)
if err != nil {
return nil, err
}
} else {
// generate random address for the node
raw := srv.cfg.Subnet.Addr().As16()
salt := make([]byte, 8)
_, err := io.ReadFull(rand.Reader, salt)
if err != nil {
return nil, err
}
copy(raw[8:], salt)
nodeAddress = netip.PrefixFrom(netip.AddrFrom16(raw), srv.cfg.Subnet.Bits())
serverbinding.Spec.SideroLink.NodeAddress = nodeAddress.String()
}
pubKey, err := wgtypes.ParseKey(req.NodePublicKey)
if err != nil {
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("error parsing Wireguard key: %s", err))
}
serverbinding.Spec.SideroLink.NodePublicKey = pubKey.String()
if err = patchHelper.Patch(ctx, &serverbinding); err != nil {
return nil, err
}
return &pb.ProvisionResponse{
ServerEndpoint: srv.cfg.WireguardEndpoint,
ServerPublicKey: srv.cfg.PublicKey.String(),
ServerAddress: srv.cfg.ServerAddress.Addr().String(),
NodeAddressPrefix: nodeAddress.String(),
}, nil
}