feat: implement Siderolink wireguard over GRPC

For #8064

Signed-off-by: Dmitriy Matrenichev <dmitry.matrenichev@siderolabs.com>
This commit is contained in:
Dmitriy Matrenichev 2024-03-05 16:45:25 +03:00
parent 9afa70baf3
commit 06e3bc0cbd
No known key found for this signature in database
GPG Key ID: 94B473337258BFD5
18 changed files with 1081 additions and 116 deletions

Binary file not shown.

View File

@ -4,8 +4,22 @@ package talos.resource.definitions.siderolink;
option go_package = "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/siderolink";
// ConfigSpec describes KubeSpan configuration..
import "common/common.proto";
// ConfigSpec describes Siderolink configuration.
message ConfigSpec {
string api_endpoint = 1;
string host = 2;
string join_token = 3;
bool insecure = 4;
bool tunnel = 5;
}
// TunnelSpec describes Siderolink GRPC Tunnel configuration.
message TunnelSpec {
string api_endpoint = 1;
string link_name = 2;
int64 mtu = 3;
common.NetIPPort node_address = 4;
}

4
go.mod
View File

@ -129,7 +129,7 @@ require (
github.com/siderolabs/grpc-proxy v0.4.0
github.com/siderolabs/kms-client v0.1.0
github.com/siderolabs/net v0.4.0
github.com/siderolabs/siderolink v0.3.4
github.com/siderolabs/siderolink v0.3.5-0.20240312123444-8866351abf8d
github.com/siderolabs/talos/pkg/machinery v1.7.0-alpha.1
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
@ -153,6 +153,7 @@ require (
golang.org/x/term v0.18.0
golang.org/x/text v0.14.0
golang.org/x/time v0.5.0
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
google.golang.org/grpc v1.62.1
google.golang.org/protobuf v1.33.0
@ -329,7 +330,6 @@ require (
golang.org/x/mod v0.15.0 // indirect
golang.org/x/tools v0.18.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect

38
go.sum
View File

@ -91,52 +91,30 @@ github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hC
github.com/armon/go-proxyproto v0.0.0-20210323213023-7e956b284f0a/go.mod h1:QmP9hvJ91BbJmGVGSbutW19IC0Q9phDCLGaomwTJbgU=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go-v2 v1.25.2 h1:/uiG1avJRgLGiQM9X3qJM8+Qa6KRGK5rRPuXE0HUM+w=
github.com/aws/aws-sdk-go-v2 v1.25.2/go.mod h1:Evoc5AsmtveRt1komDwIsjHFyrP5tDuF1D1U+6z6pNo=
github.com/aws/aws-sdk-go-v2 v1.25.3 h1:xYiLpZTQs1mzvz5PaI6uR0Wh57ippuEthxS4iK5v0n0=
github.com/aws/aws-sdk-go-v2 v1.25.3/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I=
github.com/aws/aws-sdk-go-v2/config v1.27.6 h1:WmoH1aPrxwcqAZTTnETjKr+fuvqzKd4hRrKxQUiuKP4=
github.com/aws/aws-sdk-go-v2/config v1.27.6/go.mod h1:W9RZFF2pL+OhnUSZsQS/eDMWD8v+R+yWgjj3nSlrXVU=
github.com/aws/aws-sdk-go-v2/config v1.27.7 h1:JSfb5nOQF01iOgxFI5OIKWwDiEXWTyTgg1Mm1mHi0A4=
github.com/aws/aws-sdk-go-v2/config v1.27.7/go.mod h1:PH0/cNpoMO+B04qET699o5W92Ca79fVtbUnvMIZro4I=
github.com/aws/aws-sdk-go-v2/credentials v1.17.6 h1:akhj/nSC6SEx3OmiYGG/7mAyXMem9ZNVVf+DXkikcTk=
github.com/aws/aws-sdk-go-v2/credentials v1.17.6/go.mod h1:chJZuJ7TkW4kiMwmldOJOEueBoSkUb4ynZS1d9dhygo=
github.com/aws/aws-sdk-go-v2/credentials v1.17.7 h1:WJd+ubWKoBeRh7A5iNMnxEOs982SyVKOJD+K8HIezu4=
github.com/aws/aws-sdk-go-v2/credentials v1.17.7/go.mod h1:UQi7LMR0Vhvs+44w5ec8Q+VS+cd10cjwgHwiVkE0YGU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2 h1:AK0J8iYBFeUk2Ax7O8YpLtFsfhdOByh2QIkHmigpRYk=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2/go.mod h1:iRlGzMix0SExQEviAyptRWRGdYNo3+ufW/lCzvKVTUc=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 h1:p+y7FvkK2dxS+FEwRIDHDe//ZX+jDhP8HHE50ppj4iI=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3/go.mod h1:/fYB+FZbDlwlAiynK9KDXlzZl3ANI9JkD0Uhz5FjNT4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2 h1:bNo4LagzUKbjdxE0tIcR9pMzLR2U/Tgie1Hq1HQ3iH8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2/go.mod h1:wRQv0nN6v9wDXuWThpovGQjqF1HFdcgWjporw14lS8k=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 h1:ifbIbHZyGl1alsAhPIYsHOg5MuApgqOvVeI8wIugXfs=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3/go.mod h1:oQZXg3c6SNeY6OZrDY+xHcF4VGIEoNotX2B4PrDeoJI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2 h1:EtOU5jsPdIQNP+6Q2C5e3d65NKT1PeCiQk+9OdzO12Q=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2/go.mod h1:tyF5sKccmDz0Bv4NrstEr+/9YkSPJHrcO7UsUKf7pWM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 h1:Qvodo9gHG9F3E8SfYOspPeBt0bjSbsevK8WhRAUHcoY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3/go.mod h1:vCKrdLXtybdf/uQd/YfVR2r5pcbNuEYKzMQpcxmeSJw=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.4 h1:jRiWxyuVO8PlkN72wDMVn/haVH4SDCBkUt0Lf/dxd7s=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.4/go.mod h1:Ru7vg1iQ7cR4i7SZ/JTLYN9kaXtbL69UdgG0OQWQxW0=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 h1:K/NXvIftOlX+oGgWGIa3jDyYLDNsdVhsjHmsBH2GLAQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5/go.mod h1:cl9HGLV66EnCmMNzq4sYOti+/xo8w34CsgzVtm2GgsY=
github.com/aws/aws-sdk-go-v2/service/kms v1.29.1 h1:OdjJjUWFlMZLAMl54ASxIpZdGEesY4BH3/c0HAPSFdI=
github.com/aws/aws-sdk-go-v2/service/kms v1.29.1/go.mod h1:Cbx2uxEX0bAB7SlSY+ys05ZBkEb8IbmuAOcGVmDfJFs=
github.com/aws/aws-sdk-go-v2/service/kms v1.29.2 h1:3UaqodPQqPh5XowXJ9fWM4TQqwuftYYFvej+RI5uIO8=
github.com/aws/aws-sdk-go-v2/service/kms v1.29.2/go.mod h1:elLDaj+1RNl9Ovn3dB6dWLVo5WQ+VLSUMKegl7N96fY=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.1 h1:utEGkfdQ4L6YW/ietH7111ZYglLJvS+sLriHJ1NBJEQ=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.1/go.mod h1:RsYqzYr2F2oPDdpy+PdhephuZxTfjHQe7SOBcZGoAU8=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 h1:XOPfar83RIRPEzfihnp+U6udOveKZJvPQ76SKWrLRHc=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2/go.mod h1:Vv9Xyk1KMHXrR3vNQe8W5LMFdTjSeWk0gBZBzvf3Qa0=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1 h1:9/GylMS45hGGFCcMrUZDVayQE1jYSIN6da9jo7RAYIw=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1/go.mod h1:YjAPFn4kGFqKC54VsHs5fn5B6d+PCY2tziEa3U/GB5Y=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 h1:pi0Skl6mNl2w8qWZXcdOyg197Zsf4G97U7Sso9JXGZE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2/go.mod h1:JYzLoEVeLXk+L4tn1+rrkfhkxl6mLDEVaDSvGq9og90=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.3 h1:TkiFkSVX990ryWIMBCT4kPqZEgThQe1xPU/AQXavtvU=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.3/go.mod h1:xYNauIUqSuvzlPVb3VB5no/n48YGhmlInD3Uh0Co8Zc=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 h1:Ppup1nVNAOWbBOrcoOxaxPeEnSFB2RnnQdguhXpmeQk=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4/go.mod h1:+K1rNPVyGxkRuv9NNiaZ4YhBFuyw2MMA9SlIJ1Zlpz8=
github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw=
@ -382,8 +360,6 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/nftables v0.1.0 h1:T6lS4qudrMufcNIZ8wSRrL+iuwhsKxpN+zFLxhUWOqk=
github.com/google/nftables v0.1.0/go.mod h1:b97ulCCFipUC+kSin+zygkvUVpx0vyIAwxXFdY3PlNc=
github.com/google/nftables v0.2.0 h1:PbJwaBmbVLzpeldoeUKGkE2RjstrjPKMl6oLrfEJ6/8=
github.com/google/nftables v0.2.0/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -421,8 +397,6 @@ github.com/gosuri/uiprogress v0.0.1 h1:0kpv/XY/qTmFWl/SkaJykZXrBBzwwadmW8fRb7RJS
github.com/gosuri/uiprogress v0.0.1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 h1:HcUWd006luQPljE73d5sk+/VgYPGUReEVz2y1/qylwY=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is=
@ -638,14 +612,10 @@ github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cY
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
github.com/rivo/tview v0.0.0-20240225120200-5605142ca62e h1:7ubTieBkl4KCz5ABZzh0zPkBYWPguSOHUundUsorIzQ=
github.com/rivo/tview v0.0.0-20240225120200-5605142ca62e/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss=
github.com/rivo/tview v0.0.0-20240307173318-e804876934a1 h1:bWLHTRekAy497pE7+nXSuzXwwFHI0XauRzz6roUvY+s=
github.com/rivo/tview v0.0.0-20240307173318-e804876934a1/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@ -725,8 +695,8 @@ github.com/siderolabs/net v0.4.0 h1:1bOgVay/ijPkJz4qct98nHsiB/ysLQU0KLoBC4qLm7I=
github.com/siderolabs/net v0.4.0/go.mod h1:/ibG+Hm9HU27agp5r9Q3eZicEfjquzNzQNux5uEk0kM=
github.com/siderolabs/protoenc v0.2.1 h1:BqxEmeWQeMpNP3R6WrPqDatX8sM/r4t97OP8mFmg6GA=
github.com/siderolabs/protoenc v0.2.1/go.mod h1:StTHxjet1g11GpNAWiATgc8K0HMKiFSEVVFOa/H0otc=
github.com/siderolabs/siderolink v0.3.4 h1:850JRSSrD3EEDh35h6wiSTtRiGuclEc/6k4wx/It4nU=
github.com/siderolabs/siderolink v0.3.4/go.mod h1:juxlSF9cBzeBHsOjS7hVS3s0NDpC034i/OZunVReqmo=
github.com/siderolabs/siderolink v0.3.5-0.20240312123444-8866351abf8d h1:KSNg9hpF//WW+uZ7+ersxyo7/EW/NjkZoOiah2yKt9A=
github.com/siderolabs/siderolink v0.3.5-0.20240312123444-8866351abf8d/go.mod h1:/7Dg0Nkh4q/8yqsY/VirDOTOFOqRvPikagCoyf3+Mf4=
github.com/siderolabs/tcpproxy v0.1.0 h1:IbkS9vRhjMOscc1US3M5P1RnsGKFgB6U5IzUk+4WkKA=
github.com/siderolabs/tcpproxy v0.1.0/go.mod h1:onn6CPPj/w1UNqQ0U97oRPF0CqbrgEApYCw4P9IiCW8=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
@ -1124,8 +1094,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb h1:c5tyN8sSp8jSDxdCCDXVOpJwYXXhmTkNMt+g0zTSOic=
golang.zx2c4.com/wireguard v0.0.0-20231022001213-2e0774f246fb/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=

View File

@ -12,6 +12,7 @@ import (
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/hashicorp/go-multierror"
"github.com/jsimonetti/rtnetlink"
"github.com/siderolabs/gen/pair/ordered"
@ -512,8 +513,8 @@ func (ctrl *LinkSpecController) syncLink(ctx context.Context, r controller.Runti
logger.Info("reconfigured wireguard link", zap.Int("peers", len(link.TypedSpec().Wireguard.Peers)))
// notify link status controller, as wireguard updates can't be watched via netlink API
if err = r.Modify(ctx, network.NewLinkRefresh(network.NamespaceName, network.LinkKindWireguard), func(r resource.Resource) error {
r.(*network.LinkRefresh).TypedSpec().Bump()
if err = safe.WriterModify[*network.LinkRefresh](ctx, r, network.NewLinkRefresh(network.NamespaceName, network.LinkKindWireguard), func(r *network.LinkRefresh) error {
r.TypedSpec().Bump()
return nil
}); err != nil {

View File

@ -16,6 +16,7 @@ import (
"go.uber.org/zap"
v1alpha1runtime "github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
"github.com/siderolabs/talos/internal/pkg/endpoint"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
"github.com/siderolabs/talos/pkg/machinery/resources/siderolink"
@ -55,6 +56,8 @@ func (ctrl *ConfigController) Outputs() []controller.Output {
}
// Run implements controller.Controller interface.
//
//nolint:gocyclo
func (ctrl *ConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {
for {
select {
@ -70,9 +73,20 @@ func (ctrl *ConfigController) Run(ctx context.Context, r controller.Runtime, _ *
r.StartTrackingOutputs()
if endpoint := ctrl.apiEndpoint(cfg); endpoint != "" {
if ep := ctrl.apiEndpoint(cfg); ep != "" {
var parsed endpoint.Endpoint
parsed, err = endpoint.Parse(ep)
if err != nil {
return fmt.Errorf("failed to parse siderolink API endpoint: %w", err)
}
if err = safe.WriterModify(ctx, r, siderolink.NewConfig(config.NamespaceName, siderolink.ConfigID), func(c *siderolink.Config) error {
c.TypedSpec().APIEndpoint = endpoint
c.TypedSpec().APIEndpoint = ep
c.TypedSpec().Host = parsed.Host
c.TypedSpec().JoinToken = parsed.GetParam("jointoken")
c.TypedSpec().Insecure = parsed.Insecure
c.TypedSpec().Tunnel = parsed.GetParam("grpc_tunnel") == "true" || parsed.GetParam("grpc_tunnel") == "y"
return nil
}); err != nil {

View File

@ -7,9 +7,11 @@ package siderolink_test
import (
"net/url"
"testing"
"time"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/resource/rtestutils"
"github.com/siderolabs/gen/xtesting/must"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
@ -32,6 +34,7 @@ func TestConfigSuite(t *testing.T) {
AfterSetup: func(suite *ctest.DefaultSuite) {
suite.Require().NoError(suite.Runtime().RegisterController(&siderolinkctrl.ConfigController{}))
},
Timeout: time.Second,
},
})
}
@ -41,7 +44,7 @@ func (suite *ConfigSuite) TestConfig() {
siderolinkConfig := &siderolinkcfg.ConfigV1Alpha1{
APIUrlConfig: meta.URL{
URL: must(url.Parse("https://api.sidero.dev")),
URL: must.Value(url.Parse("https://api.sidero.dev"))(suite.T()),
},
}
@ -56,10 +59,23 @@ func (suite *ConfigSuite) TestConfig() {
})
}
func must[T any](t T, err error) T {
if err != nil {
panic(err)
func (suite *ConfigSuite) TestConfigTunnel() {
rtestutils.AssertNoResource[*siderolink.Config](suite.Ctx(), suite.T(), suite.State(), siderolink.ConfigID)
siderolinkConfig := &siderolinkcfg.ConfigV1Alpha1{
APIUrlConfig: meta.URL{
URL: must.Value(url.Parse("https://api.sidero.dev?grpc_tunnel=true"))(suite.T()),
},
}
return t
cfg, err := container.New(siderolinkConfig)
suite.Require().NoError(err)
suite.Require().NoError(suite.State().Create(suite.Ctx(), config.NewMachineConfig(cfg)))
rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{siderolink.ConfigID},
func(c *siderolink.Config, assert *assert.Assertions) {
assert.Equal("https://api.sidero.dev?grpc_tunnel=true", c.TypedSpec().APIEndpoint)
assert.True(c.TypedSpec().Tunnel)
})
}

View File

@ -30,7 +30,6 @@ import (
"google.golang.org/grpc/credentials/insecure"
networkutils "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/utils"
"github.com/siderolabs/talos/internal/pkg/endpoint"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/nethelpers"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
@ -68,6 +67,10 @@ func (ctrl *ManagerController) Outputs() []controller.Output {
Type: network.LinkSpecType,
Kind: controller.OutputShared,
},
{
Type: siderolink.TunnelType,
Kind: controller.OutputExclusive,
},
}
}
@ -185,7 +188,7 @@ func (ctrl *ManagerController) Run(ctx context.Context, r controller.Runtime, lo
zap.String("next_peer_endpoint", ctrl.pd.PeekNextEndpoint()),
)
if err := safe.WriterModify(ctx, r, linkSpec,
if err = safe.WriterModify(ctx, r, linkSpec,
func(res *network.LinkSpec) error {
spec := res.TypedSpec()
@ -194,7 +197,7 @@ func (ctrl *ManagerController) Run(ctx context.Context, r controller.Runtime, lo
spec.Type = nethelpers.LinkNone
spec.Kind = "wireguard"
spec.Up = true
spec.Logical = true
spec.Logical = ctrl.pd.grpcPeerAddrPort == ""
spec.MTU = wireguard.LinkMTU
spec.Wireguard = network.WireguardSpec{
@ -219,7 +222,7 @@ func (ctrl *ManagerController) Run(ctx context.Context, r controller.Runtime, lo
return fmt.Errorf("error creating siderolink spec: %w", err)
}
if err := safe.WriterModify(ctx, r, addressSpec,
if err = safe.WriterModify(ctx, r, addressSpec,
func(res *network.AddressSpec) error {
spec := res.TypedSpec()
@ -235,6 +238,32 @@ func (ctrl *ManagerController) Run(ctx context.Context, r controller.Runtime, lo
return fmt.Errorf("error creating address spec: %w", err)
}
if ctrl.pd.grpcPeerAddrPort != "" {
var ourAddr netip.AddrPort
ourAddr, err = netip.ParseAddrPort(ctrl.pd.grpcPeerAddrPort)
if err != nil {
return err
}
if err = safe.WriterModify(ctx, r, siderolink.NewTunnel(),
func(tunnel *siderolink.Tunnel) error {
tunnel.TypedSpec().APIEndpoint = ctrl.pd.apiEndpont
tunnel.TypedSpec().LinkName = constants.SideroLinkName
tunnel.TypedSpec().MTU = wireguard.LinkMTU
tunnel.TypedSpec().NodeAddress = ourAddr
return nil
},
); err != nil {
return fmt.Errorf("error creating tunnel spec: %w", err)
}
} else {
if err = r.Destroy(ctx, siderolink.NewTunnel().Metadata()); err != nil && !state.IsNotFoundError(err) {
return fmt.Errorf("error destroying tunnel spec: %w", err)
}
}
keepLinkSpecSet := map[resource.ID]struct{}{
linkSpec.Metadata().ID(): {},
}
@ -283,20 +312,6 @@ func (ctrl *ManagerController) provision(ctx context.Context, r controller.Runti
}
nodeUUID := sysInfo.TypedSpec().UUID
stringEndpoint := cfg.TypedSpec().APIEndpoint
parsedEndpoint, err := endpoint.Parse(stringEndpoint)
if err != nil {
return optional.None[provisionData](), fmt.Errorf("failed to parse siderolink endpoint: %w", err)
}
var transportCredentials credentials.TransportCredentials
if parsedEndpoint.Insecure {
transportCredentials = insecure.NewCredentials()
} else {
transportCredentials = credentials.NewTLS(&tls.Config{})
}
provision := func() (*pb.ProvisionResponse, error) {
connCtx, connCtxCancel := context.WithTimeout(ctx, 10*time.Second)
@ -304,12 +319,12 @@ func (ctrl *ManagerController) provision(ctx context.Context, r controller.Runti
conn, connErr := grpc.DialContext(
connCtx,
parsedEndpoint.Host,
grpc.WithTransportCredentials(transportCredentials),
cfg.TypedSpec().Host,
withTransportCredentials(cfg.TypedSpec().Insecure),
grpc.WithSharedWriteBuffer(true),
)
if connErr != nil {
return nil, fmt.Errorf("error dialing SideroLink endpoint %q: %w", stringEndpoint, connErr)
return nil, fmt.Errorf("error dialing SideroLink endpoint %q: %w", cfg.TypedSpec().Host, connErr)
}
defer func() {
@ -323,15 +338,22 @@ func (ctrl *ManagerController) provision(ctx context.Context, r controller.Runti
return nil, fmt.Errorf("failed to get unique token: %w", rdrErr)
}
sideroLinkClient := pb.NewProvisionServiceClient(conn)
request := &pb.ProvisionRequest{
NodeUuid: nodeUUID,
NodePublicKey: ctrl.nodeKey.PublicKey().String(),
NodeUniqueToken: pointer.To(uniqTokenRes.TypedSpec().Token),
TalosVersion: pointer.To(version.Tag),
var wgOverGRPC *bool
if cfg.TypedSpec().Tunnel {
wgOverGRPC = pointer.To(true)
}
token := parsedEndpoint.GetParam("jointoken")
sideroLinkClient := pb.NewProvisionServiceClient(conn)
request := &pb.ProvisionRequest{
NodeUuid: nodeUUID,
NodePublicKey: ctrl.nodeKey.PublicKey().String(),
NodeUniqueToken: pointer.To(uniqTokenRes.TypedSpec().Token),
TalosVersion: pointer.To(version.Tag),
WireguardOverGrpc: wgOverGRPC,
}
token := cfg.TypedSpec().JoinToken
if token != "" {
request.JoinToken = pointer.To(token)
@ -347,11 +369,12 @@ func (ctrl *ManagerController) provision(ctx context.Context, r controller.Runti
return optional.Some(provisionData{
nodeUUID: nodeUUID,
apiEndpont: stringEndpoint,
apiEndpont: cfg.TypedSpec().APIEndpoint,
ServerAddress: resp.ServerAddress,
ServerPublicKey: resp.ServerPublicKey,
NodeAddressPrefix: resp.NodeAddressPrefix,
endpoints: resp.GetEndpoints(),
grpcPeerAddrPort: resp.GrpcPeerAddrPort,
}), nil
}
@ -362,6 +385,7 @@ type provisionData struct {
ServerPublicKey string
NodeAddressPrefix string
endpoints []string
grpcPeerAddrPort string
}
func (d *provisionData) IsEmpty() bool {
@ -476,3 +500,15 @@ func (ctrl *ManagerController) shouldReconnect(wgClient *wgctrl.Client) (bool, e
return since >= wireguard.PeerDownInterval, nil
}
func withTransportCredentials(insec bool) grpc.DialOption {
var transportCredentials credentials.TransportCredentials
if insec {
transportCredentials = insecure.NewCredentials()
} else {
transportCredentials = credentials.NewTLS(&tls.Config{})
}
return grpc.WithTransportCredentials(transportCredentials)
}

View File

@ -0,0 +1,217 @@
// 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"
"fmt"
"net/netip"
"sync/atomic"
"time"
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/safe"
"github.com/cosi-project/runtime/pkg/state"
"github.com/siderolabs/gen/optional"
"github.com/siderolabs/siderolink/pkg/wgtunnel"
"github.com/siderolabs/siderolink/pkg/wgtunnel/wgbind"
"github.com/siderolabs/siderolink/pkg/wgtunnel/wggrpc"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
"github.com/siderolabs/talos/internal/pkg/ctxutil"
"github.com/siderolabs/talos/internal/pkg/endpoint"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
"github.com/siderolabs/talos/pkg/machinery/resources/siderolink"
)
// UserspaceWireguardController imlements a controller that manages a Wireguard over GRPC tunnel in userspace.
type UserspaceWireguardController struct {
RelayRetryTimeout time.Duration
DebugDataStream bool
}
// Name implements controller.Controller interface.
func (ctrl *UserspaceWireguardController) Name() string {
return "siderolink.UserspaceWireguardController"
}
// Inputs implements controller.Controller interface.
func (ctrl *UserspaceWireguardController) Inputs() []controller.Input {
return []controller.Input{
{
Namespace: config.NamespaceName,
Type: siderolink.TunnelType,
ID: optional.Some(siderolink.TunnelID),
Kind: controller.InputWeak,
},
}
}
// Outputs implements controller.Controller interface.
func (ctrl *UserspaceWireguardController) Outputs() []controller.Output {
return []controller.Output{}
}
// Run implements controller.Controller interface.
//
//nolint:gocyclo
func (ctrl *UserspaceWireguardController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
eg, ctx := errgroup.WithContext(ctx)
var (
tunnelDevice atomic.Pointer[wgtunnel.TunnelDevice]
tunnelRelay atomic.Pointer[tunnelProps]
)
defer func() {
tunnelRelay.Load().Relay().Close()
tunnelDevice.Load().Close()
}()
const (
// maxPendingServerMessages is the maximum number of messages that can be pending in the queue before blocking.
maxPendingServerMessages = 100
// maxPendingClientMessages is the maximum number of messages that can be pending in the ring before being overwritten.
maxPendingClientMessages = 100
)
qp := wgbind.NewQueuePair(maxPendingServerMessages, maxPendingClientMessages)
for {
select {
case <-ctx.Done():
return ctxutil.Cause(ctx)
case <-r.EventCh():
}
res, err := safe.ReaderGetByID[*siderolink.Tunnel](ctx, r, siderolink.TunnelID)
if err != nil {
if state.IsNotFoundError(err) {
tunnelRelay.Load().Relay().Close()
tunnelDevice.Load().Close()
continue
}
return fmt.Errorf("failed to read link spec: %w", err)
}
if td := tunnelDevice.Load(); td.IsClosed() {
td.Close()
td, err = wgtunnel.NewTunnelDevice(res.TypedSpec().LinkName, res.TypedSpec().MTU, qp, ctrl.makeLogger(logger))
if err != nil {
return fmt.Errorf("failed to create tunnel device: %w", err)
}
tunnelDevice.Store(td)
logger.Info("wg over grpc tunnel device created", zap.String("link_name", res.TypedSpec().LinkName))
eg.Go(func() error {
logger.Debug("running tunnel device")
defer logger.Debug("tunnel device exited")
return td.Run()
})
}
ep, err := endpoint.Parse(res.TypedSpec().APIEndpoint)
if err != nil {
return fmt.Errorf("failed to parse siderolink API endpoint: %w", err)
}
if tn := tunnelRelay.Load(); tn.Relay().IsClosed() || tn.DstHost() != ep.Host || tn.OurAddrPort() != res.TypedSpec().NodeAddress {
tn.Relay().Close()
dstHost := ep.Host
ourAddrPort := res.TypedSpec().NodeAddress
logger.Info(
"updating tunnel relay",
zap.String("old_endpoint", tn.DstHost()),
zap.Stringer("old_node_address", tn.OurAddrPort()),
zap.String("new_endpoint", dstHost),
zap.Stringer("new_node_address", ourAddrPort),
)
relay, err := wggrpc.NewRelayToHost(dstHost, ctrl.RelayRetryTimeout, qp, ourAddrPort, withTransportCredentials(ep.Insecure))
if err != nil {
return fmt.Errorf("failed to create tunnel relay: %w", err)
}
tunnelRelay.Store(newTunnelProps(relay, dstHost, ourAddrPort))
eg.Go(func() error {
logger.Debug("running tunnel relay")
err := relay.Run(ctx, ctrl.makeLogger(logger))
if err == nil {
logger.Info("tunnel relay exited gracefully",
zap.String("endpoint", dstHost),
zap.Stringer("node_address", ourAddrPort),
)
return nil
}
// Relay returned an error, close the relay and print the error, device should be kept running.
relay.Close()
logger.Error("tunnel relay failed, retrying",
zap.String("endpoint", dstHost),
zap.Stringer("node_address", ourAddrPort),
zap.Error(err),
)
return nil
})
}
}
}
// makeLogger ensures that we do not spam like crazy into our ring buffer loggers unless we explicitly want to.
func (ctrl *UserspaceWireguardController) makeLogger(logger *zap.Logger) *zap.Logger {
if ctrl.DebugDataStream {
return logger
}
return logger.WithOptions(zap.IncreaseLevel(zap.InfoLevel))
}
func newTunnelProps(relay *wggrpc.Relay, dstHost string, ourAddrPort netip.AddrPort) *tunnelProps {
return &tunnelProps{relay: relay, dstHost: dstHost, ourAddrPort: ourAddrPort}
}
type tunnelProps struct {
relay *wggrpc.Relay
dstHost string
ourAddrPort netip.AddrPort
}
func (t *tunnelProps) Relay() *wggrpc.Relay {
if t == nil {
return nil
}
return t.relay
}
func (t *tunnelProps) DstHost() string {
if t == nil {
return "<invalid_host>"
}
return t.dstHost
}
func (t *tunnelProps) OurAddrPort() netip.AddrPort {
if t == nil {
return netip.AddrPort{}
}
return t.ourAddrPort
}

View File

@ -319,6 +319,9 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
},
&siderolink.ManagerController{},
&siderolink.UserspaceWireguardController{
RelayRetryTimeout: 10 * time.Second,
},
&timecontrollers.AdjtimeStatusController{
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
},

View File

@ -204,6 +204,7 @@ func NewState() (*State, error) {
&secrets.OSRoot{},
&secrets.Trustd{},
&siderolink.Config{},
&siderolink.Tunnel{},
&time.AdjtimeStatus{},
&time.Status{},
&v1alpha1.AcquireConfigSpec{},

View File

@ -12,6 +12,8 @@ import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
common "github.com/siderolabs/talos/pkg/machinery/api/common"
)
const (
@ -21,13 +23,17 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// ConfigSpec describes KubeSpan configuration..
// ConfigSpec describes Siderolink configuration.
type ConfigSpec struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ApiEndpoint string `protobuf:"bytes,1,opt,name=api_endpoint,json=apiEndpoint,proto3" json:"api_endpoint,omitempty"`
Host string `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"`
JoinToken string `protobuf:"bytes,3,opt,name=join_token,json=joinToken,proto3" json:"join_token,omitempty"`
Insecure bool `protobuf:"varint,4,opt,name=insecure,proto3" json:"insecure,omitempty"`
Tunnel bool `protobuf:"varint,5,opt,name=tunnel,proto3" json:"tunnel,omitempty"`
}
func (x *ConfigSpec) Reset() {
@ -69,6 +75,106 @@ func (x *ConfigSpec) GetApiEndpoint() string {
return ""
}
func (x *ConfigSpec) GetHost() string {
if x != nil {
return x.Host
}
return ""
}
func (x *ConfigSpec) GetJoinToken() string {
if x != nil {
return x.JoinToken
}
return ""
}
func (x *ConfigSpec) GetInsecure() bool {
if x != nil {
return x.Insecure
}
return false
}
func (x *ConfigSpec) GetTunnel() bool {
if x != nil {
return x.Tunnel
}
return false
}
// TunnelSpec describes Siderolink GRPC Tunnel configuration.
type TunnelSpec struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ApiEndpoint string `protobuf:"bytes,1,opt,name=api_endpoint,json=apiEndpoint,proto3" json:"api_endpoint,omitempty"`
LinkName string `protobuf:"bytes,2,opt,name=link_name,json=linkName,proto3" json:"link_name,omitempty"`
Mtu int64 `protobuf:"varint,3,opt,name=mtu,proto3" json:"mtu,omitempty"`
NodeAddress *common.NetIPPort `protobuf:"bytes,4,opt,name=node_address,json=nodeAddress,proto3" json:"node_address,omitempty"`
}
func (x *TunnelSpec) Reset() {
*x = TunnelSpec{}
if protoimpl.UnsafeEnabled {
mi := &file_resource_definitions_siderolink_siderolink_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TunnelSpec) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TunnelSpec) ProtoMessage() {}
func (x *TunnelSpec) ProtoReflect() protoreflect.Message {
mi := &file_resource_definitions_siderolink_siderolink_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TunnelSpec.ProtoReflect.Descriptor instead.
func (*TunnelSpec) Descriptor() ([]byte, []int) {
return file_resource_definitions_siderolink_siderolink_proto_rawDescGZIP(), []int{1}
}
func (x *TunnelSpec) GetApiEndpoint() string {
if x != nil {
return x.ApiEndpoint
}
return ""
}
func (x *TunnelSpec) GetLinkName() string {
if x != nil {
return x.LinkName
}
return ""
}
func (x *TunnelSpec) GetMtu() int64 {
if x != nil {
return x.Mtu
}
return 0
}
func (x *TunnelSpec) GetNodeAddress() *common.NetIPPort {
if x != nil {
return x.NodeAddress
}
return nil
}
var File_resource_definitions_siderolink_siderolink_proto protoreflect.FileDescriptor
var file_resource_definitions_siderolink_siderolink_proto_rawDesc = []byte{
@ -77,16 +183,33 @@ var file_resource_definitions_siderolink_siderolink_proto_rawDesc = []byte{
0x6b, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x25, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x73,
0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x2f, 0x0a, 0x0a, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x70, 0x69, 0x5f, 0x65,
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61,
0x70, 0x69, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x4f, 0x5a, 0x4d, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c,
0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61,
0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x69, 0x6e, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x69, 0x6e, 0x6b, 0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x96,
0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x21, 0x0a,
0x0c, 0x61, 0x70, 0x69, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x70, 0x69, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x68, 0x6f, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x74, 0x6f, 0x6b,
0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18,
0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12,
0x16, 0x0a, 0x06, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
0x06, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x94, 0x01, 0x0a, 0x0a, 0x54, 0x75, 0x6e, 0x6e,
0x65, 0x6c, 0x53, 0x70, 0x65, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x70, 0x69, 0x5f, 0x65, 0x6e,
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x70,
0x69, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x69, 0x6e,
0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x69,
0x6e, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18, 0x03, 0x20,
0x01, 0x28, 0x03, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x12, 0x34, 0x0a, 0x0c, 0x6e, 0x6f, 0x64, 0x65,
0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x50, 0x50, 0x6f, 0x72,
0x74, 0x52, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x4f,
0x5a, 0x4d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64,
0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b,
0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f,
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x69, 0x6e, 0x6b, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -101,16 +224,19 @@ func file_resource_definitions_siderolink_siderolink_proto_rawDescGZIP() []byte
return file_resource_definitions_siderolink_siderolink_proto_rawDescData
}
var file_resource_definitions_siderolink_siderolink_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_resource_definitions_siderolink_siderolink_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_resource_definitions_siderolink_siderolink_proto_goTypes = []interface{}{
(*ConfigSpec)(nil), // 0: talos.resource.definitions.siderolink.ConfigSpec
(*ConfigSpec)(nil), // 0: talos.resource.definitions.siderolink.ConfigSpec
(*TunnelSpec)(nil), // 1: talos.resource.definitions.siderolink.TunnelSpec
(*common.NetIPPort)(nil), // 2: common.NetIPPort
}
var file_resource_definitions_siderolink_siderolink_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
2, // 0: talos.resource.definitions.siderolink.TunnelSpec.node_address:type_name -> common.NetIPPort
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_resource_definitions_siderolink_siderolink_proto_init() }
@ -131,6 +257,18 @@ func file_resource_definitions_siderolink_siderolink_proto_init() {
return nil
}
}
file_resource_definitions_siderolink_siderolink_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TunnelSpec); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
@ -138,7 +276,7 @@ func file_resource_definitions_siderolink_siderolink_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_resource_definitions_siderolink_siderolink_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},

View File

@ -9,7 +9,10 @@ import (
io "io"
protohelpers "github.com/planetscale/vtprotobuf/protohelpers"
proto "google.golang.org/protobuf/proto"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
common "github.com/siderolabs/talos/pkg/machinery/api/common"
)
const (
@ -49,6 +52,114 @@ func (m *ConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if m.Tunnel {
i--
if m.Tunnel {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x28
}
if m.Insecure {
i--
if m.Insecure {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x20
}
if len(m.JoinToken) > 0 {
i -= len(m.JoinToken)
copy(dAtA[i:], m.JoinToken)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.JoinToken)))
i--
dAtA[i] = 0x1a
}
if len(m.Host) > 0 {
i -= len(m.Host)
copy(dAtA[i:], m.Host)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Host)))
i--
dAtA[i] = 0x12
}
if len(m.ApiEndpoint) > 0 {
i -= len(m.ApiEndpoint)
copy(dAtA[i:], m.ApiEndpoint)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ApiEndpoint)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *TunnelSpec) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *TunnelSpec) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *TunnelSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if m.NodeAddress != nil {
if vtmsg, ok := interface{}(m.NodeAddress).(interface {
MarshalToSizedBufferVT([]byte) (int, error)
}); ok {
size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
} else {
encoded, err := proto.Marshal(m.NodeAddress)
if err != nil {
return 0, err
}
i -= len(encoded)
copy(dAtA[i:], encoded)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))
}
i--
dAtA[i] = 0x22
}
if m.Mtu != 0 {
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mtu))
i--
dAtA[i] = 0x18
}
if len(m.LinkName) > 0 {
i -= len(m.LinkName)
copy(dAtA[i:], m.LinkName)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LinkName)))
i--
dAtA[i] = 0x12
}
if len(m.ApiEndpoint) > 0 {
i -= len(m.ApiEndpoint)
copy(dAtA[i:], m.ApiEndpoint)
@ -69,6 +180,51 @@ func (m *ConfigSpec) SizeVT() (n int) {
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.Host)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.JoinToken)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
if m.Insecure {
n += 2
}
if m.Tunnel {
n += 2
}
n += len(m.unknownFields)
return n
}
func (m *TunnelSpec) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.ApiEndpoint)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.LinkName)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
if m.Mtu != 0 {
n += 1 + protohelpers.SizeOfVarint(uint64(m.Mtu))
}
if m.NodeAddress != nil {
if size, ok := interface{}(m.NodeAddress).(interface {
SizeVT() int
}); ok {
l = size.SizeVT()
} else {
l = proto.Size(m.NodeAddress)
}
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
@ -134,6 +290,288 @@ func (m *ConfigSpec) UnmarshalVT(dAtA []byte) error {
}
m.ApiEndpoint = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Host", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Host = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field JoinToken", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.JoinToken = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Insecure", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.Insecure = bool(v != 0)
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Tunnel", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.Tunnel = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *TunnelSpec) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: TunnelSpec: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: TunnelSpec: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ApiEndpoint", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ApiEndpoint = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field LinkName", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.LinkName = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Mtu", wireType)
}
m.Mtu = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Mtu |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field NodeAddress", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.NodeAddress == nil {
m.NodeAddress = &common.NetIPPort{}
}
if unmarshal, ok := interface{}(m.NodeAddress).(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.NodeAddress); err != nil {
return err
}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])

View File

@ -5,8 +5,9 @@
package network
import (
"cmp"
"net/netip"
"sort"
"slices"
"time"
"github.com/siderolabs/talos/pkg/machinery/nethelpers"
@ -180,25 +181,15 @@ func (spec *WireguardSpec) Equal(other *WireguardSpec) bool {
// Sort the spec so that comparison is possible.
func (spec *WireguardSpec) Sort() {
sort.Slice(spec.Peers, func(i, j int) bool {
return spec.Peers[i].PublicKey < spec.Peers[j].PublicKey
})
slices.SortFunc(spec.Peers, func(a, b WireguardPeer) int { return cmp.Compare(a.PublicKey, b.PublicKey) })
for k := range spec.Peers {
k := k
sort.Slice(spec.Peers[k].AllowedIPs, func(i, j int) bool {
left := spec.Peers[k].AllowedIPs[i]
right := spec.Peers[k].AllowedIPs[j]
switch left.Addr().Compare(right.Addr()) {
case -1:
return true
case 0:
return left.Bits() < right.Bits()
default:
return false
slices.SortFunc(spec.Peers[k].AllowedIPs, func(left, right netip.Prefix) int {
if res := left.Addr().Compare(right.Addr()); res != 0 {
return res
}
return cmp.Compare(left.Bits(), right.Bits())
})
}
}

View File

@ -2,7 +2,7 @@
// 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/.
// Code generated by "deep-copy -type ConfigSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
// Code generated by "deep-copy -type ConfigSpec -type TunnelSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
package siderolink
@ -11,3 +11,9 @@ func (o ConfigSpec) DeepCopy() ConfigSpec {
var cp ConfigSpec = o
return cp
}
// DeepCopy generates a deep copy of TunnelSpec.
func (o TunnelSpec) DeepCopy() TunnelSpec {
var cp TunnelSpec = o
return cp
}

View File

@ -15,7 +15,7 @@ import (
"github.com/siderolabs/talos/pkg/machinery/resources/config"
)
//go:generate deep-copy -type ConfigSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
//go:generate deep-copy -type ConfigSpec -type TunnelSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
// ConfigType is type of Config resource.
const ConfigType = resource.Type("SiderolinkConfigs.siderolink.talos.dev")
@ -23,14 +23,18 @@ const ConfigType = resource.Type("SiderolinkConfigs.siderolink.talos.dev")
// ConfigID the singleton config resource ID.
const ConfigID = resource.ID("siderolink")
// Config resource holds KubeSpan configuration.
// Config resource holds Siderolink configuration.
type Config = typed.Resource[ConfigSpec, ConfigExtension]
// ConfigSpec describes KubeSpan configuration..
// ConfigSpec describes Siderolink configuration.
//
//gotagsrewrite:gen
type ConfigSpec struct {
APIEndpoint string `yaml:"apiEndpoint" protobuf:"1"`
Host string `yaml:"host" protobuf:"2"`
JoinToken string `yaml:"joinToken" protobuf:"3"`
Insecure bool `yaml:"insecure" protobuf:"4"`
Tunnel bool `yaml:"tunnel" protobuf:"5"`
}
// NewConfig initializes a Config resource.
@ -55,6 +59,10 @@ func (ConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {
Name: "API Endpoint",
JSONPath: `{.apiEndpoint}`,
},
{
Name: "Tunnel",
JSONPath: `{.tunnel}`,
},
},
Sensitivity: meta.Sensitive,
}

View File

@ -0,0 +1,89 @@
// 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 (
"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"
"github.com/cosi-project/runtime/pkg/resource/typed"
"github.com/siderolabs/talos/pkg/machinery/proto"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
)
// TunnelType is type of Tunnel resource.
const TunnelType = resource.Type("SiderolinkTunnels.siderolink.talos.dev")
// TunnelID the singleton tunnel resource ID.
const TunnelID = resource.ID("siderolink-tunnel")
// Tunnel resource holds Siderolink GRPC Tunnel configuration.
type Tunnel = typed.Resource[TunnelSpec, TunnelExtension]
// TunnelSpec describes Siderolink GRPC Tunnel configuration.
//
//gotagsrewrite:gen
type TunnelSpec struct {
// APIEndpoint is the Siderolink WireGuard over GRPC endpoint.
APIEndpoint string `yaml:"apiEndpoint" protobuf:"1"`
// LinkName is the name to use for WireGuard tunnel.
LinkName string `yaml:"linkName" protobuf:"2"`
// MTU is the maximum transmission unit for the tunnel.
MTU int `yaml:"mtu" protobuf:"3"`
// NodeAddress is the virtual address of our node. It's used to identify our node in the WireGuard GRPC streamer.
// It's not the address of the actual WireGuard interface.
NodeAddress netip.AddrPort `yaml:"nodeAddress" protobuf:"4"`
}
// NewTunnel initializes a Config resource.
func NewTunnel() *Tunnel {
return typed.NewResource[TunnelSpec, TunnelExtension](
resource.NewMetadata(config.NamespaceName, TunnelType, TunnelID, resource.VersionUndefined),
TunnelSpec{},
)
}
// TunnelExtension provides auxiliary methods for Tunnel.
type TunnelExtension struct{}
// ResourceDefinition implements [typed.Extension] interface.
func (TunnelExtension) ResourceDefinition() meta.ResourceDefinitionSpec {
return meta.ResourceDefinitionSpec{
Type: TunnelType,
Aliases: []resource.Type{},
DefaultNamespace: config.NamespaceName,
PrintColumns: []meta.PrintColumn{
{
Name: "API Endpoint",
JSONPath: `{.apiEndpoint}`,
},
{
Name: "Interface name",
JSONPath: `{.ifaceName}`,
},
{
Name: "MTU",
JSONPath: `{.mtu}`,
},
{
Name: "Node address",
JSONPath: `{.nodeAddress}`,
},
},
Sensitivity: meta.Sensitive,
}
}
func init() {
proto.RegisterDefaultTypes()
err := protobuf.RegisterDynamic[TunnelSpec](TunnelType, &Tunnel{})
if err != nil {
panic(err)
}
}

View File

@ -243,6 +243,7 @@ description: Talos gRPC API reference.
- [resource/definitions/siderolink/siderolink.proto](#resource/definitions/siderolink/siderolink.proto)
- [ConfigSpec](#talos.resource.definitions.siderolink.ConfigSpec)
- [TunnelSpec](#talos.resource.definitions.siderolink.TunnelSpec)
- [resource/definitions/time/time.proto](#resource/definitions/time/time.proto)
- [AdjtimeStatusSpec](#talos.resource.definitions.time.AdjtimeStatusSpec)
@ -4361,12 +4362,34 @@ TrustdCertsSpec describes etcd certs secrets.
<a name="talos.resource.definitions.siderolink.ConfigSpec"></a>
### ConfigSpec
ConfigSpec describes KubeSpan configuration..
ConfigSpec describes Siderolink configuration.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| api_endpoint | [string](#string) | | |
| host | [string](#string) | | |
| join_token | [string](#string) | | |
| insecure | [bool](#bool) | | |
| tunnel | [bool](#bool) | | |
<a name="talos.resource.definitions.siderolink.TunnelSpec"></a>
### TunnelSpec
TunnelSpec describes Siderolink GRPC Tunnel configuration.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| api_endpoint | [string](#string) | | |
| link_name | [string](#string) | | |
| mtu | [int64](#int64) | | |
| node_address | [common.NetIPPort](#common.NetIPPort) | | |