mirror of
https://github.com/siderolabs/talos.git
synced 2026-03-09 15:41:54 +01:00
chore: add endpoints balancer controller
This PR adds support for creating a list of API endpoints (each is pair of host and port). It gets them from - Machine config cluster endpoint. - Localhost with LocalAPIServerPort if machine is control panel. - netip.Addr[0] and port from affiliates if they are control panels. For #7191 Signed-off-by: Dmitriy Matrenichev <dmitry.matrenichev@siderolabs.com>
This commit is contained in:
parent
423a31ac9d
commit
8a02ecd4cb
@ -131,7 +131,6 @@ linters-settings:
|
||||
replace-local: true
|
||||
replace-allow-list:
|
||||
- gopkg.in/yaml.v3
|
||||
- inet.af/tcpproxy
|
||||
retract-allow-no-explanation: false
|
||||
exclude-forbidden: true
|
||||
|
||||
|
||||
@ -872,7 +872,7 @@ COPY --from=rootfs / /
|
||||
ARG TESTPKGS
|
||||
ENV PLATFORM container
|
||||
ARG GO_LDFLAGS
|
||||
RUN --security=insecure --mount=type=cache,id=testspace,target=/tmp --mount=type=cache,target=/.cache go test -v \
|
||||
RUN --security=insecure --mount=type=cache,id=testspace,target=/tmp --mount=type=cache,target=/.cache go test -failfast -v \
|
||||
-ldflags "${GO_LDFLAGS}" \
|
||||
-covermode=atomic -coverprofile=coverage.txt -coverpkg=${TESTPKGS} -count 1 -p 4 ${TESTPKGS}
|
||||
FROM scratch AS unit-tests
|
||||
|
||||
@ -16,6 +16,7 @@ message AffiliateSpec {
|
||||
string operating_system = 5;
|
||||
talos.resource.definitions.enums.MachineType machine_type = 6;
|
||||
KubeSpanAffiliateSpec kube_span = 7;
|
||||
ControlPlane control_plane = 8;
|
||||
}
|
||||
|
||||
// ConfigSpec describes KubeSpan configuration.
|
||||
@ -29,6 +30,11 @@ message ConfigSpec {
|
||||
string service_cluster_id = 7;
|
||||
}
|
||||
|
||||
// ControlPlane describes ControlPlane data if any.
|
||||
message ControlPlane {
|
||||
int64 api_server_port = 1;
|
||||
}
|
||||
|
||||
// IdentitySpec describes status of rendered secrets.
|
||||
//
|
||||
// Note: IdentitySpec is persisted on disk in the STATE partition,
|
||||
@ -58,5 +64,6 @@ message MemberSpec {
|
||||
string hostname = 3;
|
||||
talos.resource.definitions.enums.MachineType machine_type = 4;
|
||||
string operating_system = 5;
|
||||
ControlPlane control_plane = 6;
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +23,17 @@ message APIServerConfigSpec {
|
||||
string advertised_address = 11;
|
||||
}
|
||||
|
||||
// APIServerEndpoint holds data for control plane endpoint.
|
||||
message APIServerEndpoint {
|
||||
string host = 1;
|
||||
uint32 port = 2;
|
||||
}
|
||||
|
||||
// APIServerEndpointsSpec describes APIServerEndpoints configuration.
|
||||
message APIServerEndpointsSpec {
|
||||
repeated APIServerEndpoint endpoints = 1;
|
||||
}
|
||||
|
||||
// AdmissionControlConfigSpec is configuration for kube-apiserver.
|
||||
message AdmissionControlConfigSpec {
|
||||
repeated AdmissionPluginSpec config = 1;
|
||||
|
||||
8
go.mod
8
go.mod
@ -37,7 +37,7 @@ require (
|
||||
github.com/containernetworking/plugins v1.3.0
|
||||
github.com/coreos/go-iptables v0.6.0
|
||||
github.com/coreos/go-semver v0.3.1
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.3
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.4
|
||||
github.com/docker/distribution v2.8.2+incompatible
|
||||
github.com/docker/docker v24.0.2+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
@ -87,8 +87,8 @@ require (
|
||||
github.com/safchain/ethtool v0.3.0
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.17
|
||||
github.com/siderolabs/crypto v0.4.0
|
||||
github.com/siderolabs/discovery-api v0.1.2
|
||||
github.com/siderolabs/discovery-client v0.1.4
|
||||
github.com/siderolabs/discovery-api v0.1.3
|
||||
github.com/siderolabs/discovery-client v0.1.5
|
||||
github.com/siderolabs/gen v0.4.5
|
||||
github.com/siderolabs/go-blockdevice v0.4.5
|
||||
github.com/siderolabs/go-circular v0.1.0
|
||||
@ -110,7 +110,7 @@ require (
|
||||
github.com/siderolabs/talos/pkg/machinery v1.5.0-alpha.0
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.3
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/u-root/u-root v0.11.0
|
||||
github.com/ulikunitz/xz v0.5.11
|
||||
github.com/vishvananda/netlink v1.2.1-beta.2
|
||||
|
||||
16
go.sum
16
go.sum
@ -458,8 +458,8 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.3 h1:8IDeG7b64OCTMHlngEKWTHTYKCfJ1oMVDxP3y0yuKbU=
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.3/go.mod h1:g+0MZ3+2MIUkUL7JYTqgYeo5f4j7dAuGem6apjBJ1XU=
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.4 h1:TXrn1ka+pw2YeywKZjA9b4mNoz4a9HBX9ovR4YtkDGc=
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.4/go.mod h1:GubXzK7vQFe4VyrWL/eXaMU4T1pXBx9KoDj0GJz6miw=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
@ -1134,10 +1134,10 @@ github.com/sethgrid/pester v1.2.0/go.mod h1:hEUINb4RqvDxtoCaU0BNT/HV4ig5kfgOasrf
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/siderolabs/crypto v0.4.0 h1:o1KIR1KyevUcY9nbJlSyQAj7+p+rveGGF8LjAAFMtjc=
|
||||
github.com/siderolabs/crypto v0.4.0/go.mod h1:itZpBsJ9i0aH8jiHAuSlKCal7hni7X1aDYo6vGVl5LY=
|
||||
github.com/siderolabs/discovery-api v0.1.2 h1:PxJhl9s2qpPgjO65bgOdRovBvRg/RuZu935nbYszIYc=
|
||||
github.com/siderolabs/discovery-api v0.1.2/go.mod h1:JnJg4h1HbAhOazQl0lYHEjrg63rg/cf9r2te6/DqUxo=
|
||||
github.com/siderolabs/discovery-client v0.1.4 h1:5e/4tVsCMTdz1YlynI2ebhSJ9PHhmD3y+aGIsKjDlSA=
|
||||
github.com/siderolabs/discovery-client v0.1.4/go.mod h1:TmrvPz89JyhQT4vrIzAqx/v89zxikdYmhpC0GQsiH3Y=
|
||||
github.com/siderolabs/discovery-api v0.1.3 h1:37ue+0w2A7Q2FrhyuDbfdhL4VPvDTpCzUYGvibhMwv0=
|
||||
github.com/siderolabs/discovery-api v0.1.3/go.mod h1:fC6DOJwYQy2QsMCLLTvoScKmBCMNza+VwK2/RHLsoHU=
|
||||
github.com/siderolabs/discovery-client v0.1.5 h1:CyaOOynanZdB29v46lyEOaNfPoBnKjjEBwdYbyCZEh4=
|
||||
github.com/siderolabs/discovery-client v0.1.5/go.mod h1:XFSNX7ADu+4r3j/m299V6pP7f4vEDnSJJhgc5yZE73g=
|
||||
github.com/siderolabs/gen v0.4.5 h1:rwXUVJlL7hYza1LrSVXfT905ZC9Rgei37jMKKs/+eP0=
|
||||
github.com/siderolabs/gen v0.4.5/go.mod h1:wS8tFq7sn5vqKAuyS30vJUig3tX5v6q79VG4KfUnILM=
|
||||
github.com/siderolabs/go-api-signature v0.2.4 h1:s+K0GtaPHql4LdZzL72QvwPMzffY+KB0mszORDK+5/w=
|
||||
@ -1238,8 +1238,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
|
||||
@ -10,6 +10,8 @@ import (
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/controller"
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
"github.com/siderolabs/gen/channel"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
|
||||
@ -47,23 +49,21 @@ func (ctrl *AffiliateMergeController) Outputs() []controller.Output {
|
||||
// Run implements controller.Controller interface.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (ctrl *AffiliateMergeController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
func (ctrl *AffiliateMergeController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-r.EventCh():
|
||||
if _, ok := channel.RecvWithContext(ctx, r.EventCh()); !ok && ctx.Err() != nil {
|
||||
return nil //nolint:nilerr
|
||||
}
|
||||
|
||||
mergedAffiliates := make(map[resource.ID]*cluster.AffiliateSpec)
|
||||
|
||||
rawAffiliates, err := r.List(ctx, resource.NewMetadata(cluster.RawNamespaceName, cluster.AffiliateType, "", resource.VersionUndefined))
|
||||
rawAffiliates, err := safe.ReaderList[*cluster.Affiliate](ctx, r, resource.NewMetadata(cluster.RawNamespaceName, cluster.AffiliateType, "", resource.VersionUndefined))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing affiliates")
|
||||
}
|
||||
|
||||
for _, rawAffiliate := range rawAffiliates.Items {
|
||||
affiliateSpec := rawAffiliate.(*cluster.Affiliate).TypedSpec()
|
||||
mergedAffiliates := make(map[resource.ID]*cluster.AffiliateSpec, rawAffiliates.Len())
|
||||
|
||||
for it := safe.IteratorFromList(rawAffiliates); it.Next(); {
|
||||
affiliateSpec := it.Value().TypedSpec()
|
||||
id := affiliateSpec.NodeID
|
||||
|
||||
if affiliate, ok := mergedAffiliates[id]; ok {
|
||||
@ -73,13 +73,13 @@ func (ctrl *AffiliateMergeController) Run(ctx context.Context, r controller.Runt
|
||||
}
|
||||
}
|
||||
|
||||
touchedIDs := make(map[resource.ID]struct{})
|
||||
touchedIDs := make(map[resource.ID]struct{}, len(mergedAffiliates))
|
||||
|
||||
for id, affiliateSpec := range mergedAffiliates {
|
||||
affiliateSpec := affiliateSpec
|
||||
|
||||
if err = r.Modify(ctx, cluster.NewAffiliate(cluster.NamespaceName, id), func(res resource.Resource) error {
|
||||
*res.(*cluster.Affiliate).TypedSpec() = *affiliateSpec
|
||||
if err = safe.WriterModify(ctx, r, cluster.NewAffiliate(cluster.NamespaceName, id), func(res *cluster.Affiliate) error {
|
||||
*res.TypedSpec() = *affiliateSpec
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -90,12 +90,14 @@ func (ctrl *AffiliateMergeController) Run(ctx context.Context, r controller.Runt
|
||||
}
|
||||
|
||||
// list keys for cleanup
|
||||
list, err := r.List(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.AffiliateType, "", resource.VersionUndefined))
|
||||
list, err := safe.ReaderListAll[*cluster.Affiliate](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing resources: %w", err)
|
||||
}
|
||||
|
||||
for _, res := range list.Items {
|
||||
for it := safe.IteratorFromList(list); it.Next(); {
|
||||
res := it.Value()
|
||||
|
||||
if res.Metadata().Owner() != ctrl.Name() {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -7,13 +7,13 @@ package cluster_test
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/siderolabs/go-retry/retry"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
|
||||
)
|
||||
@ -40,6 +40,7 @@ func (suite *AffiliateMergeSuite) TestReconcileDefault() {
|
||||
AdditionalAddresses: []netip.Prefix{netip.MustParsePrefix("10.244.3.1/24")},
|
||||
Endpoints: []netip.AddrPort{netip.MustParseAddrPort("10.0.0.2:51820"), netip.MustParseAddrPort("192.168.3.4:51820")},
|
||||
},
|
||||
ControlPlane: &cluster.ControlPlane{APIServerPort: 6443},
|
||||
}
|
||||
|
||||
affiliate2 := cluster.NewAffiliate(cluster.RawNamespaceName, "service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC")
|
||||
@ -65,67 +66,63 @@ func (suite *AffiliateMergeSuite) TestReconcileDefault() {
|
||||
}
|
||||
|
||||
// there should be two merged affiliates: one from affiliate1+affiliate2, and another from affiliate3
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewAffiliate(cluster.NamespaceName, affiliate1.TypedSpec().NodeID).Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Affiliate).TypedSpec()
|
||||
ctest.AssertResource(
|
||||
suite,
|
||||
affiliate1.TypedSpec().NodeID,
|
||||
func(r *cluster.Affiliate, asrt *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
suite.Assert().Equal(affiliate1.TypedSpec().NodeID, spec.NodeID)
|
||||
suite.Assert().Equal([]netip.Addr{netip.MustParseAddr("192.168.3.4"), netip.MustParseAddr("10.5.0.2")}, spec.Addresses)
|
||||
suite.Assert().Equal("foo.com", spec.Hostname)
|
||||
suite.Assert().Equal("bar", spec.Nodename)
|
||||
suite.Assert().Equal(machine.TypeControlPlane, spec.MachineType)
|
||||
suite.Assert().Equal(netip.MustParseAddr("fd50:8d60:4238:6302:f857:23ff:fe21:d1e0"), spec.KubeSpan.Address)
|
||||
suite.Assert().Equal("PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=", spec.KubeSpan.PublicKey)
|
||||
suite.Assert().Equal([]netip.Prefix{netip.MustParsePrefix("10.244.3.1/24")}, spec.KubeSpan.AdditionalAddresses)
|
||||
suite.Assert().Equal([]netip.AddrPort{netip.MustParseAddrPort("10.0.0.2:51820"), netip.MustParseAddrPort("192.168.3.4:51820")}, spec.KubeSpan.Endpoints)
|
||||
asrt.Equal(affiliate1.TypedSpec().NodeID, spec.NodeID)
|
||||
asrt.Equal([]netip.Addr{netip.MustParseAddr("192.168.3.4"), netip.MustParseAddr("10.5.0.2")}, spec.Addresses)
|
||||
asrt.Equal("foo.com", spec.Hostname)
|
||||
asrt.Equal("bar", spec.Nodename)
|
||||
asrt.Equal(machine.TypeControlPlane, spec.MachineType)
|
||||
asrt.Equal(netip.MustParseAddr("fd50:8d60:4238:6302:f857:23ff:fe21:d1e0"), spec.KubeSpan.Address)
|
||||
asrt.Equal("PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=", spec.KubeSpan.PublicKey)
|
||||
asrt.Equal([]netip.Prefix{netip.MustParsePrefix("10.244.3.1/24")}, spec.KubeSpan.AdditionalAddresses)
|
||||
asrt.Equal([]netip.AddrPort{netip.MustParseAddrPort("10.0.0.2:51820"), netip.MustParseAddrPort("192.168.3.4:51820")}, spec.KubeSpan.Endpoints)
|
||||
asrt.Equal(&cluster.ControlPlane{APIServerPort: 6443}, spec.ControlPlane)
|
||||
},
|
||||
)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
ctest.AssertResource(
|
||||
suite,
|
||||
affiliate3.TypedSpec().NodeID,
|
||||
func(r *cluster.Affiliate, asrt *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewAffiliate(cluster.NamespaceName, affiliate3.TypedSpec().NodeID).Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Affiliate).TypedSpec()
|
||||
|
||||
suite.Assert().Equal(affiliate3.TypedSpec().NodeID, spec.NodeID)
|
||||
suite.Assert().Equal([]netip.Addr{netip.MustParseAddr("192.168.3.5")}, spec.Addresses)
|
||||
suite.Assert().Equal("worker-1", spec.Hostname)
|
||||
suite.Assert().Equal("worker-1", spec.Nodename)
|
||||
suite.Assert().Equal(machine.TypeWorker, spec.MachineType)
|
||||
suite.Assert().Zero(spec.KubeSpan.PublicKey)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
asrt.Equal(affiliate3.TypedSpec().NodeID, spec.NodeID)
|
||||
asrt.Equal([]netip.Addr{netip.MustParseAddr("192.168.3.5")}, spec.Addresses)
|
||||
asrt.Equal("worker-1", spec.Hostname)
|
||||
asrt.Equal("worker-1", spec.Nodename)
|
||||
asrt.Equal(machine.TypeWorker, spec.MachineType)
|
||||
asrt.Zero(spec.KubeSpan.PublicKey)
|
||||
asrt.Nil(spec.ControlPlane)
|
||||
},
|
||||
)
|
||||
|
||||
// remove affiliate2, KubeSpan information should eventually go away
|
||||
suite.Require().NoError(suite.state.Destroy(suite.ctx, affiliate1.Metadata()))
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewAffiliate(cluster.NamespaceName, affiliate1.TypedSpec().NodeID).Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Affiliate).TypedSpec()
|
||||
ctest.AssertResource(
|
||||
suite,
|
||||
affiliate1.TypedSpec().NodeID,
|
||||
func(r *cluster.Affiliate, asrt *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
suite.Assert().Equal(affiliate1.TypedSpec().NodeID, spec.NodeID)
|
||||
|
||||
if spec.KubeSpan.PublicKey != "" {
|
||||
return retry.ExpectedErrorf("not reconciled yet")
|
||||
}
|
||||
|
||||
suite.Assert().Zero(spec.KubeSpan.Address)
|
||||
suite.Assert().Zero(spec.KubeSpan.PublicKey)
|
||||
suite.Assert().Zero(spec.KubeSpan.AdditionalAddresses)
|
||||
suite.Assert().Zero(spec.KubeSpan.Endpoints)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
asrt.Equal(affiliate1.TypedSpec().NodeID, spec.NodeID)
|
||||
asrt.Zero(spec.KubeSpan.Address)
|
||||
asrt.Zero(spec.KubeSpan.PublicKey)
|
||||
asrt.Zero(spec.KubeSpan.AdditionalAddresses)
|
||||
asrt.Zero(spec.KubeSpan.Endpoints)
|
||||
asrt.Nil(spec.ControlPlane)
|
||||
},
|
||||
)
|
||||
|
||||
// remove affiliate3, merged affiliate should be removed
|
||||
suite.Require().NoError(suite.state.Destroy(suite.ctx, affiliate3.Metadata()))
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertNoResource(*cluster.NewAffiliate(cluster.NamespaceName, affiliate3.TypedSpec().NodeID).Metadata()),
|
||||
))
|
||||
ctest.AssertNoResource[*cluster.Affiliate](suite, affiliate3.TypedSpec().NodeID)
|
||||
}
|
||||
|
||||
func TestAffiliateMergeSuite(t *testing.T) {
|
||||
|
||||
@ -11,18 +11,24 @@ import (
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/controller"
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
|
||||
)
|
||||
|
||||
func cleanupAffiliates(ctx context.Context, ctrl controller.Controller, r controller.Runtime, touchedIDs map[resource.ID]struct{}) error {
|
||||
// list keys for cleanup
|
||||
list, err := r.List(ctx, resource.NewMetadata(cluster.RawNamespaceName, cluster.AffiliateType, "", resource.VersionUndefined))
|
||||
list, err := safe.ReaderList[*cluster.Affiliate](
|
||||
ctx,
|
||||
r,
|
||||
resource.NewMetadata(cluster.RawNamespaceName, cluster.AffiliateType, "", resource.VersionUndefined),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing resources: %w", err)
|
||||
}
|
||||
|
||||
for _, res := range list.Items {
|
||||
for it := safe.IteratorFromList(list); it.Next(); {
|
||||
res := it.Value()
|
||||
if res.Metadata().Owner() != ctrl.Name() {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -71,21 +71,6 @@ func (suite *ClusterSuite) assertResource(md resource.Metadata, check func(res r
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ClusterSuite) assertNoResource(md resource.Metadata) func() error {
|
||||
return func() error {
|
||||
_, err := suite.state.Get(suite.ctx, md)
|
||||
if err == nil {
|
||||
return retry.ExpectedErrorf("resource %s still exists", md)
|
||||
}
|
||||
|
||||
if state.IsNotFoundError(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ClusterSuite) TearDownTest() {
|
||||
suite.T().Log("tear down")
|
||||
|
||||
|
||||
@ -13,6 +13,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/cosi-project/runtime/pkg/state"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"go.uber.org/zap"
|
||||
@ -67,17 +68,17 @@ func (ctrl *ConfigController) Run(ctx context.Context, r controller.Runtime, log
|
||||
}
|
||||
}
|
||||
|
||||
touchedIDs := make(map[resource.ID]struct{})
|
||||
touchedIDs := map[resource.ID]struct{}{}
|
||||
|
||||
if cfg != nil {
|
||||
c := cfg.(*config.MachineConfig).Config()
|
||||
|
||||
if err = r.Modify(ctx, cluster.NewConfig(config.NamespaceName, cluster.ConfigID), func(res resource.Resource) error {
|
||||
res.(*cluster.Config).TypedSpec().DiscoveryEnabled = c.Cluster().Discovery().Enabled()
|
||||
if err = safe.WriterModify(ctx, r, cluster.NewConfig(config.NamespaceName, cluster.ConfigID), func(res *cluster.Config) error {
|
||||
res.TypedSpec().DiscoveryEnabled = c.Cluster().Discovery().Enabled()
|
||||
|
||||
if c.Cluster().Discovery().Enabled() {
|
||||
res.(*cluster.Config).TypedSpec().RegistryKubernetesEnabled = c.Cluster().Discovery().Registries().Kubernetes().Enabled()
|
||||
res.(*cluster.Config).TypedSpec().RegistryServiceEnabled = c.Cluster().Discovery().Registries().Service().Enabled()
|
||||
res.TypedSpec().RegistryKubernetesEnabled = c.Cluster().Discovery().Registries().Kubernetes().Enabled()
|
||||
res.TypedSpec().RegistryServiceEnabled = c.Cluster().Discovery().Registries().Service().Enabled()
|
||||
|
||||
if c.Cluster().Discovery().Registries().Service().Enabled() {
|
||||
var u *url.URL
|
||||
@ -98,24 +99,24 @@ func (ctrl *ConfigController) Run(ctx context.Context, r controller.Runtime, log
|
||||
}
|
||||
}
|
||||
|
||||
res.(*cluster.Config).TypedSpec().ServiceEndpoint = net.JoinHostPort(host, port)
|
||||
res.(*cluster.Config).TypedSpec().ServiceEndpointInsecure = u.Scheme == "http"
|
||||
res.TypedSpec().ServiceEndpoint = net.JoinHostPort(host, port)
|
||||
res.TypedSpec().ServiceEndpointInsecure = u.Scheme == "http"
|
||||
|
||||
res.(*cluster.Config).TypedSpec().ServiceEncryptionKey, err = base64.StdEncoding.DecodeString(c.Cluster().Secret())
|
||||
res.TypedSpec().ServiceEncryptionKey, err = base64.StdEncoding.DecodeString(c.Cluster().Secret())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res.(*cluster.Config).TypedSpec().ServiceClusterID = c.Cluster().ID()
|
||||
res.TypedSpec().ServiceClusterID = c.Cluster().ID()
|
||||
} else {
|
||||
res.(*cluster.Config).TypedSpec().ServiceEndpoint = ""
|
||||
res.(*cluster.Config).TypedSpec().ServiceEndpointInsecure = false
|
||||
res.(*cluster.Config).TypedSpec().ServiceEncryptionKey = nil
|
||||
res.(*cluster.Config).TypedSpec().ServiceClusterID = ""
|
||||
res.TypedSpec().ServiceEndpoint = ""
|
||||
res.TypedSpec().ServiceEndpointInsecure = false
|
||||
res.TypedSpec().ServiceEncryptionKey = nil
|
||||
res.TypedSpec().ServiceClusterID = ""
|
||||
}
|
||||
} else {
|
||||
res.(*cluster.Config).TypedSpec().RegistryKubernetesEnabled = false
|
||||
res.(*cluster.Config).TypedSpec().RegistryServiceEnabled = false
|
||||
res.TypedSpec().RegistryKubernetesEnabled = false
|
||||
res.TypedSpec().RegistryServiceEnabled = false
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@ -133,7 +133,7 @@ func (ctrl *DiscoveryServiceController) Run(ctx context.Context, r controller.Ru
|
||||
}
|
||||
}
|
||||
|
||||
discoveryConfig, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, cluster.ConfigType, cluster.ConfigID, resource.VersionUndefined))
|
||||
discoveryConfig, err := safe.ReaderGetByID[*cluster.Config](ctx, r, cluster.ConfigID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting discovery config: %w", err)
|
||||
@ -142,7 +142,7 @@ func (ctrl *DiscoveryServiceController) Run(ctx context.Context, r controller.Ru
|
||||
continue
|
||||
}
|
||||
|
||||
if !discoveryConfig.(*cluster.Config).TypedSpec().RegistryServiceEnabled {
|
||||
if !discoveryConfig.TypedSpec().RegistryServiceEnabled {
|
||||
// if discovery is disabled cleanup existing resources
|
||||
if err = cleanupAffiliates(ctx, ctrl, r, nil); err != nil {
|
||||
return err
|
||||
@ -164,7 +164,7 @@ func (ctrl *DiscoveryServiceController) Run(ctx context.Context, r controller.Ru
|
||||
continue
|
||||
}
|
||||
|
||||
identity, err := r.Get(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.IdentityType, cluster.LocalIdentity, resource.VersionUndefined))
|
||||
identity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting local identity: %w", err)
|
||||
@ -173,7 +173,7 @@ func (ctrl *DiscoveryServiceController) Run(ctx context.Context, r controller.Ru
|
||||
continue
|
||||
}
|
||||
|
||||
localAffiliateID := identity.(*cluster.Identity).TypedSpec().NodeID
|
||||
localAffiliateID := identity.TypedSpec().NodeID
|
||||
|
||||
if ctrl.localAffiliateID != localAffiliateID {
|
||||
ctrl.localAffiliateID = localAffiliateID
|
||||
@ -203,7 +203,7 @@ func (ctrl *DiscoveryServiceController) Run(ctx context.Context, r controller.Ru
|
||||
}
|
||||
}
|
||||
|
||||
affiliate, err := r.Get(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.AffiliateType, ctrl.localAffiliateID, resource.VersionUndefined))
|
||||
affiliate, err := safe.ReaderGetByID[*cluster.Affiliate](ctx, r, ctrl.localAffiliateID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting local affiliate: %w", err)
|
||||
@ -212,9 +212,9 @@ func (ctrl *DiscoveryServiceController) Run(ctx context.Context, r controller.Ru
|
||||
continue
|
||||
}
|
||||
|
||||
affiliateSpec := affiliate.(*cluster.Affiliate).TypedSpec()
|
||||
affiliateSpec := affiliate.TypedSpec()
|
||||
|
||||
otherEndpointsList, err := r.List(ctx, resource.NewMetadata(kubespan.NamespaceName, kubespan.EndpointType, "", resource.VersionUndefined))
|
||||
otherEndpointsList, err := safe.ReaderListAll[*kubespan.Endpoint](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing endpoints: %w", err)
|
||||
}
|
||||
@ -225,20 +225,20 @@ func (ctrl *DiscoveryServiceController) Run(ctx context.Context, r controller.Ru
|
||||
}
|
||||
|
||||
if client == nil {
|
||||
var cipher cipher.Block
|
||||
var cipherBlock cipher.Block
|
||||
|
||||
cipher, err = aes.NewCipher(discoveryConfig.(*cluster.Config).TypedSpec().ServiceEncryptionKey)
|
||||
cipherBlock, err = aes.NewCipher(discoveryConfig.TypedSpec().ServiceEncryptionKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error initializing AES cipher: %w", err)
|
||||
}
|
||||
|
||||
client, err = discoveryclient.NewClient(discoveryclient.Options{
|
||||
Cipher: cipher,
|
||||
Endpoint: discoveryConfig.(*cluster.Config).TypedSpec().ServiceEndpoint,
|
||||
ClusterID: discoveryConfig.(*cluster.Config).TypedSpec().ServiceClusterID,
|
||||
Cipher: cipherBlock,
|
||||
Endpoint: discoveryConfig.TypedSpec().ServiceEndpoint,
|
||||
ClusterID: discoveryConfig.TypedSpec().ServiceClusterID,
|
||||
AffiliateID: localAffiliateID,
|
||||
TTL: defaultDiscoveryTTL,
|
||||
Insecure: discoveryConfig.(*cluster.Config).TypedSpec().ServiceEndpointInsecure,
|
||||
Insecure: discoveryConfig.TypedSpec().ServiceEndpointInsecure,
|
||||
ClientVersion: version.Tag,
|
||||
})
|
||||
if err != nil {
|
||||
@ -306,8 +306,8 @@ func (ctrl *DiscoveryServiceController) Run(ctx context.Context, r controller.Ru
|
||||
|
||||
discoveredAffiliate := discoveredAffiliate
|
||||
|
||||
if err = r.Modify(ctx, cluster.NewAffiliate(cluster.RawNamespaceName, id), func(res resource.Resource) error {
|
||||
*res.(*cluster.Affiliate).TypedSpec() = specAffiliate(discoveredAffiliate.Affiliate, discoveredAffiliate.Endpoints)
|
||||
if err = safe.WriterModify(ctx, r, cluster.NewAffiliate(cluster.RawNamespaceName, id), func(res *cluster.Affiliate) error {
|
||||
*res.TypedSpec() = specAffiliate(discoveredAffiliate.Affiliate, discoveredAffiliate.Endpoints)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -327,9 +327,7 @@ func (ctrl *DiscoveryServiceController) Run(ctx context.Context, r controller.Ru
|
||||
|
||||
func pbAffiliate(affiliate *cluster.AffiliateSpec) *pb.Affiliate {
|
||||
addresses := slices.Map(affiliate.Addresses, func(address netip.Addr) []byte {
|
||||
result, _ := address.MarshalBinary() //nolint:errcheck // doesn't fail
|
||||
|
||||
return result
|
||||
return takeResult(address.MarshalBinary())
|
||||
})
|
||||
|
||||
var kubeSpan *pb.KubeSpan
|
||||
@ -337,21 +335,14 @@ func pbAffiliate(affiliate *cluster.AffiliateSpec) *pb.Affiliate {
|
||||
if affiliate.KubeSpan.PublicKey != "" {
|
||||
kubeSpan = &pb.KubeSpan{
|
||||
PublicKey: affiliate.KubeSpan.PublicKey,
|
||||
Address: takeResult(affiliate.KubeSpan.Address.MarshalBinary()),
|
||||
AdditionalAddresses: slices.Map(affiliate.KubeSpan.AdditionalAddresses, func(address netip.Prefix) *pb.IPPrefix {
|
||||
return &pb.IPPrefix{
|
||||
Bits: uint32(address.Bits()),
|
||||
Ip: takeResult(address.Addr().MarshalBinary()),
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
kubeSpan.Address, _ = affiliate.KubeSpan.Address.MarshalBinary() //nolint:errcheck // doesn't fail
|
||||
|
||||
additionalAddresses := make([]*pb.IPPrefix, len(affiliate.KubeSpan.AdditionalAddresses))
|
||||
|
||||
for i := range additionalAddresses {
|
||||
additionalAddresses[i] = &pb.IPPrefix{
|
||||
Bits: uint32(affiliate.KubeSpan.AdditionalAddresses[i].Bits()),
|
||||
}
|
||||
|
||||
additionalAddresses[i].Ip, _ = affiliate.KubeSpan.AdditionalAddresses[i].Addr().MarshalBinary() //nolint:errcheck // doesn't fail
|
||||
}
|
||||
|
||||
kubeSpan.AdditionalAddresses = additionalAddresses
|
||||
}
|
||||
|
||||
return &pb.Affiliate{
|
||||
@ -362,47 +353,48 @@ func pbAffiliate(affiliate *cluster.AffiliateSpec) *pb.Affiliate {
|
||||
MachineType: affiliate.MachineType.String(),
|
||||
OperatingSystem: affiliate.OperatingSystem,
|
||||
Kubespan: kubeSpan,
|
||||
ControlPlane: toPlane(affiliate.ControlPlane),
|
||||
}
|
||||
}
|
||||
|
||||
func toPlane(data *cluster.ControlPlane) *pb.ControlPlane {
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &pb.ControlPlane{ApiServerPort: uint32(data.APIServerPort)}
|
||||
}
|
||||
|
||||
func pbEndpoints(affiliate *cluster.AffiliateSpec) []*pb.Endpoint {
|
||||
if affiliate.KubeSpan.PublicKey == "" || len(affiliate.KubeSpan.Endpoints) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]*pb.Endpoint, len(affiliate.KubeSpan.Endpoints))
|
||||
|
||||
for i := range result {
|
||||
result[i] = &pb.Endpoint{
|
||||
Port: uint32(affiliate.KubeSpan.Endpoints[i].Port()),
|
||||
return slices.Map(affiliate.KubeSpan.Endpoints, func(endpoint netip.AddrPort) *pb.Endpoint {
|
||||
return &pb.Endpoint{
|
||||
Port: uint32(endpoint.Port()),
|
||||
Ip: takeResult(endpoint.Addr().MarshalBinary()),
|
||||
}
|
||||
|
||||
result[i].Ip, _ = affiliate.KubeSpan.Endpoints[i].Addr().MarshalBinary() //nolint:errcheck // doesn't fail
|
||||
}
|
||||
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
func pbOtherEndpoints(otherEndpointsList resource.List) []discoveryclient.Endpoint {
|
||||
if len(otherEndpointsList.Items) == 0 {
|
||||
func pbOtherEndpoints(otherEndpointsList safe.List[*kubespan.Endpoint]) []discoveryclient.Endpoint {
|
||||
if otherEndpointsList.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]discoveryclient.Endpoint, 0, len(otherEndpointsList.Items))
|
||||
result := make([]discoveryclient.Endpoint, 0, otherEndpointsList.Len())
|
||||
|
||||
for _, res := range otherEndpointsList.Items {
|
||||
endpoint := res.(*kubespan.Endpoint).TypedSpec()
|
||||
|
||||
encodedEndpoint := &pb.Endpoint{
|
||||
Port: uint32(endpoint.Endpoint.Port()),
|
||||
}
|
||||
|
||||
encodedEndpoint.Ip, _ = endpoint.Endpoint.Addr().MarshalBinary() //nolint:errcheck // doesn't fail
|
||||
for it := safe.IteratorFromList(otherEndpointsList); it.Next(); {
|
||||
endpoint := it.Value().TypedSpec()
|
||||
|
||||
result = append(result, discoveryclient.Endpoint{
|
||||
AffiliateID: endpoint.AffiliateID,
|
||||
Endpoints: []*pb.Endpoint{
|
||||
encodedEndpoint,
|
||||
{
|
||||
Port: uint32(endpoint.Endpoint.Port()),
|
||||
Ip: takeResult(endpoint.Endpoint.Addr().MarshalBinary()),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -456,10 +448,10 @@ func specAffiliate(affiliate *pb.Affiliate, endpoints []*pb.Endpoint) cluster.Af
|
||||
Hostname: affiliate.Hostname,
|
||||
Nodename: affiliate.Nodename,
|
||||
OperatingSystem: affiliate.OperatingSystem,
|
||||
MachineType: takeResult(machine.ParseType(affiliate.MachineType)), // ignore parse error (machine.TypeUnknown)
|
||||
ControlPlane: fromControlPlane(affiliate.ControlPlane),
|
||||
}
|
||||
|
||||
result.MachineType, _ = machine.ParseType(affiliate.MachineType) //nolint:errcheck // ignore parse error (machine.TypeUnknown)
|
||||
|
||||
result.Addresses = make([]netip.Addr, 0, len(affiliate.Addresses))
|
||||
|
||||
for i := range affiliate.Addresses {
|
||||
@ -497,3 +489,15 @@ func specAffiliate(affiliate *pb.Affiliate, endpoints []*pb.Endpoint) cluster.Af
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func fromControlPlane(plane *pb.ControlPlane) *cluster.ControlPlane {
|
||||
if plane == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &cluster.ControlPlane{APIServerPort: int(plane.ApiServerPort)}
|
||||
}
|
||||
|
||||
func takeResult[T any](arg1 T, _ error) T {
|
||||
return arg1
|
||||
}
|
||||
|
||||
@ -16,10 +16,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/resource/rtestutils"
|
||||
"github.com/siderolabs/discovery-api/api/v1alpha1/client/pb"
|
||||
"github.com/siderolabs/discovery-client/pkg/client"
|
||||
"github.com/siderolabs/go-retry/retry"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
clusteradapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster"
|
||||
@ -88,6 +89,7 @@ func (suite *DiscoveryServiceSuite) TestReconcile() {
|
||||
AdditionalAddresses: []netip.Prefix{netip.MustParsePrefix("10.244.3.1/24")},
|
||||
Endpoints: []netip.AddrPort{netip.MustParseAddrPort("10.0.0.2:51820"), netip.MustParseAddrPort("192.168.3.4:51820")},
|
||||
},
|
||||
ControlPlane: &cluster.ControlPlane{APIServerPort: 6443},
|
||||
}
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, localAffiliate))
|
||||
|
||||
@ -141,6 +143,7 @@ func (suite *DiscoveryServiceSuite) TestReconcile() {
|
||||
},
|
||||
},
|
||||
},
|
||||
ControlPlane: &pb.ControlPlane{ApiServerPort: 6443},
|
||||
}, affiliates[0].Affiliate))
|
||||
suite.Assert().True(proto.Equal(
|
||||
&pb.Endpoint{
|
||||
@ -187,9 +190,11 @@ func (suite *DiscoveryServiceSuite) TestReconcile() {
|
||||
},
|
||||
}, nil))
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewAffiliate(cluster.RawNamespaceName, "service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC").Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Affiliate).TypedSpec()
|
||||
ctest.AssertResource(
|
||||
suite,
|
||||
"service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC",
|
||||
func(r *cluster.Affiliate, asrt *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
suite.Assert().Equal("7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC", spec.NodeID)
|
||||
suite.Assert().Equal([]netip.Addr{netip.MustParseAddr("192.168.3.5")}, spec.Addresses)
|
||||
@ -201,22 +206,18 @@ func (suite *DiscoveryServiceSuite) TestReconcile() {
|
||||
suite.Assert().Equal("1CXkdhWBm58c36kTpchR8iGlXHG1ruHa5W8gsFqD8Qs=", spec.KubeSpan.PublicKey)
|
||||
suite.Assert().Equal([]netip.Prefix{netip.MustParsePrefix("10.244.4.1/24")}, spec.KubeSpan.AdditionalAddresses)
|
||||
suite.Assert().Equal([]netip.AddrPort{netip.MustParseAddrPort("192.168.3.5:51820")}, spec.KubeSpan.Endpoints)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
suite.Assert().Zero(spec.ControlPlane)
|
||||
},
|
||||
rtestutils.WithNamespace(cluster.RawNamespaceName),
|
||||
)
|
||||
|
||||
// controller should publish public IP
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*network.NewAddressStatus(cluster.NamespaceName, "service").Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*network.AddressStatus).TypedSpec()
|
||||
ctest.AssertResource(suite, "service", func(r *network.AddressStatus, assertions *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
suite.Assert().True(spec.Address.IsValid())
|
||||
suite.Assert().True(spec.Address.IsSingleIP())
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
assertions.True(spec.Address.IsValid())
|
||||
assertions.True(spec.Address.IsSingleIP())
|
||||
}, rtestutils.WithNamespace(cluster.NamespaceName))
|
||||
|
||||
// make controller inject additional endpoint via kubespan.Endpoint
|
||||
endpoint := kubespan.NewEndpoint(kubespan.NamespaceName, "1CXkdhWBm58c36kTpchR8iGlXHG1ruHa5W8gsFqD8Qs=")
|
||||
@ -226,22 +227,19 @@ func (suite *DiscoveryServiceSuite) TestReconcile() {
|
||||
}
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, endpoint))
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewAffiliate(cluster.RawNamespaceName, "service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC").Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Affiliate).TypedSpec()
|
||||
ctest.AssertResource(suite,
|
||||
"service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC",
|
||||
func(r *cluster.Affiliate, assertions *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
if len(spec.KubeSpan.Endpoints) != 2 {
|
||||
return retry.ExpectedErrorf("waiting for 2 endpoints, got %d", len(spec.KubeSpan.Endpoints))
|
||||
}
|
||||
|
||||
suite.Assert().Equal([]netip.AddrPort{
|
||||
assertions.Len(spec.KubeSpan.Endpoints, 2)
|
||||
assertions.Equal([]netip.AddrPort{
|
||||
netip.MustParseAddrPort("192.168.3.5:51820"),
|
||||
netip.MustParseAddrPort("1.1.1.1:343"),
|
||||
}, spec.KubeSpan.Endpoints)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
},
|
||||
rtestutils.WithNamespace(cluster.RawNamespaceName),
|
||||
)
|
||||
|
||||
// pretend that machine is being reset
|
||||
machineStatus := runtime.NewMachineStatus()
|
||||
@ -341,15 +339,14 @@ func (suite *DiscoveryServiceSuite) TestDisable() {
|
||||
},
|
||||
}, nil))
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewAffiliate(cluster.RawNamespaceName, "service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC").Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Affiliate).TypedSpec()
|
||||
|
||||
suite.Assert().Equal("7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC", spec.NodeID)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
ctest.AssertResource(
|
||||
suite,
|
||||
"service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC",
|
||||
func(r *cluster.Affiliate, asrt *assert.Assertions) {
|
||||
suite.Assert().Equal("7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC", r.TypedSpec().NodeID)
|
||||
},
|
||||
rtestutils.WithNamespace(cluster.RawNamespaceName),
|
||||
)
|
||||
|
||||
// now disable the service registry
|
||||
ctest.UpdateWithConflicts(suite, discoveryConfig, func(r *cluster.Config) error {
|
||||
@ -358,9 +355,11 @@ func (suite *DiscoveryServiceSuite) TestDisable() {
|
||||
return nil
|
||||
})
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertNoResource(*cluster.NewAffiliate(cluster.RawNamespaceName, "service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC").Metadata()),
|
||||
))
|
||||
ctest.AssertNoResource[*cluster.Affiliate](
|
||||
suite,
|
||||
"service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC",
|
||||
rtestutils.WithNamespace(cluster.RawNamespaceName),
|
||||
)
|
||||
|
||||
cliCtxCancel()
|
||||
suite.Assert().NoError(<-errCh)
|
||||
|
||||
@ -5,16 +5,16 @@
|
||||
package cluster_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/siderolabs/go-retry/retry"
|
||||
"github.com/siderolabs/gen/slices"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/k8s"
|
||||
@ -61,15 +61,19 @@ func (suite *EndpointSuite) TestReconcileDefault() {
|
||||
}
|
||||
|
||||
// control plane members should be translated to Endpoints
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*k8s.NewEndpoint(k8s.ControlPlaneNamespaceName, k8s.ControlPlaneDiscoveredEndpointsID).Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*k8s.Endpoint).TypedSpec()
|
||||
ctest.AssertResource(suite, k8s.ControlPlaneDiscoveredEndpointsID, func(r *k8s.Endpoint, asrt *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
suite.Assert().Equal(`["172.20.0.2" "172.20.0.3" "fd50:8d60:4238:6302:f857:23ff:fe21:d1e0" "fd50:8d60:4238:6302:f857:23ff:fe21:d1e1"]`, fmt.Sprintf("%q", spec.Addresses))
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
asrt.Equal(
|
||||
[]string{
|
||||
"172.20.0.2",
|
||||
"172.20.0.3",
|
||||
"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0",
|
||||
"fd50:8d60:4238:6302:f857:23ff:fe21:d1e1",
|
||||
},
|
||||
slices.Map(spec.Addresses, netip.Addr.String),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEndpointSuite(t *testing.T) {
|
||||
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"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/go-pointer"
|
||||
@ -58,7 +57,7 @@ func (ctrl *InfoController) Run(ctx context.Context, r controller.Runtime, logge
|
||||
case <-r.EventCh():
|
||||
}
|
||||
|
||||
cfg, err := safe.ReaderGet[*config.MachineConfig](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
|
||||
cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
continue
|
||||
|
||||
@ -10,6 +10,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/cosi-project/runtime/pkg/state"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"go.uber.org/zap"
|
||||
@ -93,7 +94,7 @@ func (ctrl *KubernetesPullController) Run(ctx context.Context, r controller.Runt
|
||||
case <-notifyCh:
|
||||
}
|
||||
|
||||
discoveryConfig, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, cluster.ConfigType, cluster.ConfigID, resource.VersionUndefined))
|
||||
discoveryConfig, err := safe.ReaderGetByID[*cluster.Config](ctx, r, cluster.ConfigID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting discovery config: %w", err)
|
||||
@ -102,7 +103,7 @@ func (ctrl *KubernetesPullController) Run(ctx context.Context, r controller.Runt
|
||||
continue
|
||||
}
|
||||
|
||||
if !discoveryConfig.(*cluster.Config).TypedSpec().RegistryKubernetesEnabled {
|
||||
if !discoveryConfig.TypedSpec().RegistryKubernetesEnabled {
|
||||
// if discovery is disabled cleanup existing resources
|
||||
if err = cleanupAffiliates(ctx, ctrl, r, nil); err != nil {
|
||||
return err
|
||||
@ -115,7 +116,7 @@ func (ctrl *KubernetesPullController) Run(ctx context.Context, r controller.Runt
|
||||
return err
|
||||
}
|
||||
|
||||
nodename, err := r.Get(ctx, resource.NewMetadata(k8s.NamespaceName, k8s.NodenameType, k8s.NodenameID, resource.VersionUndefined))
|
||||
nodename, err := safe.ReaderGetByID[*k8s.Nodename](ctx, r, k8s.NodenameID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting nodename: %w", err)
|
||||
@ -145,7 +146,7 @@ func (ctrl *KubernetesPullController) Run(ctx context.Context, r controller.Runt
|
||||
}
|
||||
}
|
||||
|
||||
affiliateSpecs, err := kubernetesRegistry.List(nodename.(*k8s.Nodename).TypedSpec().Nodename)
|
||||
affiliateSpecs, err := kubernetesRegistry.List(nodename.TypedSpec().Nodename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing affiliates: %w", err)
|
||||
}
|
||||
@ -157,8 +158,8 @@ func (ctrl *KubernetesPullController) Run(ctx context.Context, r controller.Runt
|
||||
|
||||
affilateSpec := affilateSpec
|
||||
|
||||
if err = r.Modify(ctx, cluster.NewAffiliate(cluster.RawNamespaceName, id), func(res resource.Resource) error {
|
||||
*res.(*cluster.Affiliate).TypedSpec() = *affilateSpec
|
||||
if err = safe.WriterModify(ctx, r, cluster.NewAffiliate(cluster.RawNamespaceName, id), func(res *cluster.Affiliate) error {
|
||||
*res.TypedSpec() = *affilateSpec
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
|
||||
@ -10,6 +10,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/cosi-project/runtime/pkg/state"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"go.uber.org/zap"
|
||||
@ -73,7 +74,7 @@ func (ctrl *KubernetesPushController) Run(ctx context.Context, r controller.Runt
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-r.EventCh():
|
||||
discoveryConfig, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, cluster.ConfigType, cluster.ConfigID, resource.VersionUndefined))
|
||||
discoveryConfig, err := safe.ReaderGetByID[*cluster.Config](ctx, r, cluster.ConfigID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting discovery config: %w", err)
|
||||
@ -82,7 +83,7 @@ func (ctrl *KubernetesPushController) Run(ctx context.Context, r controller.Runt
|
||||
continue
|
||||
}
|
||||
|
||||
if !discoveryConfig.(*cluster.Config).TypedSpec().RegistryKubernetesEnabled {
|
||||
if !discoveryConfig.TypedSpec().RegistryKubernetesEnabled {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -90,7 +91,7 @@ func (ctrl *KubernetesPushController) Run(ctx context.Context, r controller.Runt
|
||||
return err
|
||||
}
|
||||
|
||||
identity, err := r.Get(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.IdentityType, cluster.LocalIdentity, resource.VersionUndefined))
|
||||
identity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting local identity: %w", err)
|
||||
@ -99,7 +100,7 @@ func (ctrl *KubernetesPushController) Run(ctx context.Context, r controller.Runt
|
||||
continue
|
||||
}
|
||||
|
||||
localAffiliateID := identity.(*cluster.Identity).TypedSpec().NodeID
|
||||
localAffiliateID := identity.TypedSpec().NodeID
|
||||
|
||||
if ctrl.localAffiliateID != localAffiliateID {
|
||||
ctrl.localAffiliateID = localAffiliateID
|
||||
@ -116,7 +117,7 @@ func (ctrl *KubernetesPushController) Run(ctx context.Context, r controller.Runt
|
||||
}
|
||||
}
|
||||
|
||||
affiliate, err := r.Get(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.AffiliateType, ctrl.localAffiliateID, resource.VersionUndefined))
|
||||
affiliate, err := safe.ReaderGetByID[*cluster.Affiliate](ctx, r, ctrl.localAffiliateID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting local affiliate: %w", err)
|
||||
@ -132,7 +133,7 @@ func (ctrl *KubernetesPushController) Run(ctx context.Context, r controller.Runt
|
||||
}
|
||||
}
|
||||
|
||||
if err = registry.NewKubernetes(ctrl.kubernetesClient).Push(ctx, affiliate.(*cluster.Affiliate)); err != nil {
|
||||
if err = registry.NewKubernetes(ctrl.kubernetesClient).Push(ctx, affiliate); err != nil {
|
||||
// reset client connection
|
||||
ctrl.kubernetesClient.Close() //nolint:errcheck
|
||||
ctrl.kubernetesClient = nil
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"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/channel"
|
||||
"github.com/siderolabs/gen/slices"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"github.com/siderolabs/net"
|
||||
@ -90,6 +91,11 @@ func (ctrl *LocalAffiliateController) Inputs() []controller.Input {
|
||||
Type: network.AddressStatusType,
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
{
|
||||
Namespace: config.NamespaceName,
|
||||
Type: config.MachineConfigType,
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,188 +114,202 @@ func (ctrl *LocalAffiliateController) Outputs() []controller.Output {
|
||||
//nolint:gocyclo,cyclop
|
||||
func (ctrl *LocalAffiliateController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-r.EventCh():
|
||||
// mandatory resources to be fetched
|
||||
discoveryConfig, err := safe.ReaderGetByID[*cluster.Config](ctx, r, cluster.ConfigID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting discovery config: %w", err)
|
||||
if _, ok := channel.RecvWithContext(ctx, r.EventCh()); !ok && ctx.Err() != nil {
|
||||
return nil //nolint:nilerr
|
||||
}
|
||||
|
||||
// mandatory resources to be fetched
|
||||
discoveryConfig, err := safe.ReaderGetByID[*cluster.Config](ctx, r, cluster.ConfigID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting discovery config: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
identity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting local identity: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
hostname, err := safe.ReaderGetByID[*network.HostnameStatus](ctx, r, network.HostnameID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting hostname: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
nodename, err := safe.ReaderGetByID[*k8s.Nodename](ctx, r, k8s.NodenameID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting nodename: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
routedAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s))
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting addresses: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
currentAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s))
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting addresses: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
machineType, err := safe.ReaderGetByID[*config.MachineType](ctx, r, config.MachineTypeID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting machine type: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
machineConfig, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting machine config: %w", err)
|
||||
}
|
||||
|
||||
// optional resources (kubespan)
|
||||
kubespanIdentity, err := safe.ReaderGetByID[*kubespan.Identity](ctx, r, kubespan.LocalIdentity)
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting kubespan identity: %w", err)
|
||||
}
|
||||
|
||||
kubespanConfig, err := safe.ReaderGetByID[*kubespan.Config](ctx, r, kubespan.ConfigID)
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting kubespan config: %w", err)
|
||||
}
|
||||
|
||||
ksAdditionalAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterOnlyK8s))
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting kubespan additional addresses: %w", err)
|
||||
}
|
||||
|
||||
discoveredPublicIPs, err := safe.ReaderList[*network.AddressStatus](ctx, r, resource.NewMetadata(cluster.NamespaceName, network.AddressStatusType, "", resource.VersionUndefined))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting discovered public IP: %w", err)
|
||||
}
|
||||
|
||||
localID := identity.TypedSpec().NodeID
|
||||
|
||||
touchedIDs := map[resource.ID]struct{}{}
|
||||
|
||||
if discoveryConfig.TypedSpec().DiscoveryEnabled {
|
||||
if err = safe.WriterModify(ctx, r, cluster.NewAffiliate(cluster.NamespaceName, localID), func(res *cluster.Affiliate) error {
|
||||
spec := res.TypedSpec()
|
||||
|
||||
spec.NodeID = localID
|
||||
spec.Hostname = hostname.TypedSpec().FQDN()
|
||||
spec.Nodename = nodename.TypedSpec().Nodename
|
||||
spec.MachineType = machineType.MachineType()
|
||||
spec.OperatingSystem = fmt.Sprintf("%s (%s)", version.Name, version.Tag)
|
||||
|
||||
if machineType.MachineType().IsControlPlane() && machineConfig != nil {
|
||||
spec.ControlPlane = &cluster.ControlPlane{
|
||||
APIServerPort: machineConfig.Config().Cluster().LocalAPIServerPort(),
|
||||
}
|
||||
} else {
|
||||
spec.ControlPlane = nil
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
routedNodeIPs := routedAddresses.TypedSpec().IPs()
|
||||
currentNodeIPs := currentAddresses.TypedSpec().IPs()
|
||||
|
||||
identity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting local identity: %w", err)
|
||||
}
|
||||
spec.Addresses = routedNodeIPs
|
||||
|
||||
continue
|
||||
}
|
||||
spec.KubeSpan = cluster.KubeSpanAffiliateSpec{}
|
||||
|
||||
hostname, err := safe.ReaderGetByID[*network.HostnameStatus](ctx, r, network.HostnameID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting hostname: %w", err)
|
||||
}
|
||||
if kubespanIdentity != nil && kubespanConfig != nil {
|
||||
spec.KubeSpan.Address = kubespanIdentity.TypedSpec().Address.Addr()
|
||||
spec.KubeSpan.PublicKey = kubespanIdentity.TypedSpec().PublicKey
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
nodename, err := safe.ReaderGetByID[*k8s.Nodename](ctx, r, k8s.NodenameID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting nodename: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
routedAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s))
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting addresses: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
currentAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s))
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting addresses: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
machineType, err := safe.ReaderGetByID[*config.MachineType](ctx, r, config.MachineTypeID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting machine type: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// optional resources (kubespan)
|
||||
kubespanIdentity, err := safe.ReaderGetByID[*kubespan.Identity](ctx, r, kubespan.LocalIdentity)
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting kubespan identity: %w", err)
|
||||
}
|
||||
|
||||
kubespanConfig, err := safe.ReaderGetByID[*kubespan.Config](ctx, r, kubespan.ConfigID)
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting kubespan config: %w", err)
|
||||
}
|
||||
|
||||
ksAdditionalAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterOnlyK8s))
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting kubespan additional addresses: %w", err)
|
||||
}
|
||||
|
||||
discoveredPublicIPs, err := safe.ReaderList[*network.AddressStatus](ctx, r, resource.NewMetadata(cluster.NamespaceName, network.AddressStatusType, "", resource.VersionUndefined))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting discovered public IP: %w", err)
|
||||
}
|
||||
|
||||
localID := identity.TypedSpec().NodeID
|
||||
|
||||
touchedIDs := map[resource.ID]struct{}{}
|
||||
|
||||
if discoveryConfig.TypedSpec().DiscoveryEnabled {
|
||||
if err = safe.WriterModify(ctx, r, cluster.NewAffiliate(cluster.NamespaceName, localID), func(res *cluster.Affiliate) error {
|
||||
spec := res.TypedSpec()
|
||||
|
||||
spec.NodeID = localID
|
||||
spec.Hostname = hostname.TypedSpec().FQDN()
|
||||
spec.Nodename = nodename.TypedSpec().Nodename
|
||||
spec.MachineType = machineType.MachineType()
|
||||
spec.OperatingSystem = fmt.Sprintf("%s (%s)", version.Name, version.Tag)
|
||||
|
||||
routedNodeIPs := routedAddresses.TypedSpec().IPs()
|
||||
currentNodeIPs := currentAddresses.TypedSpec().IPs()
|
||||
|
||||
spec.Addresses = routedNodeIPs
|
||||
|
||||
spec.KubeSpan = cluster.KubeSpanAffiliateSpec{}
|
||||
|
||||
if kubespanIdentity != nil && kubespanConfig != nil {
|
||||
spec.KubeSpan.Address = kubespanIdentity.TypedSpec().Address.Addr()
|
||||
spec.KubeSpan.PublicKey = kubespanIdentity.TypedSpec().PublicKey
|
||||
|
||||
if kubespanConfig.TypedSpec().AdvertiseKubernetesNetworks && ksAdditionalAddresses != nil {
|
||||
spec.KubeSpan.AdditionalAddresses = slices.Clone(ksAdditionalAddresses.TypedSpec().Addresses)
|
||||
} else {
|
||||
spec.KubeSpan.AdditionalAddresses = nil
|
||||
}
|
||||
|
||||
endpointIPs := slices.Filter(currentNodeIPs, func(ip netip.Addr) bool {
|
||||
if ip == spec.KubeSpan.Address {
|
||||
// skip kubespan local address
|
||||
return false
|
||||
}
|
||||
|
||||
if network.IsULA(ip, network.ULASideroLink) {
|
||||
// ignore SideroLink addresses, as they are point-to-point addresses
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
// mix in discovered public IPs
|
||||
for iter := safe.IteratorFromList(discoveredPublicIPs); iter.Next(); {
|
||||
addr := iter.Value().TypedSpec().Address.Addr()
|
||||
|
||||
if slices.Contains(endpointIPs, func(a netip.Addr) bool { return addr == a }) {
|
||||
// this address is already published
|
||||
continue
|
||||
}
|
||||
|
||||
endpointIPs = append(endpointIPs, addr)
|
||||
}
|
||||
|
||||
// filter endpoints if configured
|
||||
if kubespanConfig.TypedSpec().EndpointFilters != nil {
|
||||
endpointIPs, err = net.FilterIPs(endpointIPs, kubespanConfig.TypedSpec().EndpointFilters)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error filtering KubeSpan endpoints: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
spec.KubeSpan.Endpoints = slices.Map(endpointIPs, func(addr netip.Addr) netip.AddrPort {
|
||||
return netip.AddrPortFrom(addr, constants.KubeSpanDefaultPort)
|
||||
})
|
||||
if kubespanConfig.TypedSpec().AdvertiseKubernetesNetworks && ksAdditionalAddresses != nil {
|
||||
spec.KubeSpan.AdditionalAddresses = slices.Clone(ksAdditionalAddresses.TypedSpec().Addresses)
|
||||
} else {
|
||||
spec.KubeSpan.AdditionalAddresses = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
endpointIPs := slices.Filter(currentNodeIPs, func(ip netip.Addr) bool {
|
||||
if ip == spec.KubeSpan.Address {
|
||||
// skip kubespan local address
|
||||
return false
|
||||
}
|
||||
|
||||
touchedIDs[localID] = struct{}{}
|
||||
}
|
||||
if network.IsULA(ip, network.ULASideroLink) {
|
||||
// ignore SideroLink addresses, as they are point-to-point addresses
|
||||
return false
|
||||
}
|
||||
|
||||
// list keys for cleanup
|
||||
list, err := r.List(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.AffiliateType, "", resource.VersionUndefined))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing resources: %w", err)
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
for _, res := range list.Items {
|
||||
if res.Metadata().Owner() != ctrl.Name() {
|
||||
continue
|
||||
}
|
||||
// mix in discovered public IPs
|
||||
for iter := safe.IteratorFromList(discoveredPublicIPs); iter.Next(); {
|
||||
addr := iter.Value().TypedSpec().Address.Addr()
|
||||
|
||||
if _, ok := touchedIDs[res.Metadata().ID()]; !ok {
|
||||
if err = r.Destroy(ctx, res.Metadata()); err != nil {
|
||||
return fmt.Errorf("error cleaning up specs: %w", err)
|
||||
if slices.Contains(endpointIPs, func(a netip.Addr) bool { return addr == a }) {
|
||||
// this address is already published
|
||||
continue
|
||||
}
|
||||
|
||||
endpointIPs = append(endpointIPs, addr)
|
||||
}
|
||||
|
||||
// filter endpoints if configured
|
||||
if kubespanConfig.TypedSpec().EndpointFilters != nil {
|
||||
endpointIPs, err = net.FilterIPs(endpointIPs, kubespanConfig.TypedSpec().EndpointFilters)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error filtering KubeSpan endpoints: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
spec.KubeSpan.Endpoints = slices.Map(endpointIPs, func(addr netip.Addr) netip.AddrPort {
|
||||
return netip.AddrPortFrom(addr, constants.KubeSpanDefaultPort)
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
touchedIDs[localID] = struct{}{}
|
||||
}
|
||||
|
||||
// list keys for cleanup
|
||||
list, err := safe.ReaderListAll[*cluster.Affiliate](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing resources: %w", err)
|
||||
}
|
||||
|
||||
for it := safe.IteratorFromList(list); it.Next(); {
|
||||
res := it.Value()
|
||||
|
||||
if res.Metadata().Owner() != ctrl.Name() {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := touchedIDs[res.Metadata().ID()]; !ok {
|
||||
if err = r.Destroy(ctx, res.Metadata()); err != nil {
|
||||
return fmt.Errorf("error cleaning up specs: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,17 +7,20 @@ package cluster_test
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/siderolabs/go-retry/retry"
|
||||
"github.com/siderolabs/gen/slices"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
clusteradapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster"
|
||||
kubespanadapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/kubespan"
|
||||
clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/container"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/config"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/k8s"
|
||||
@ -35,6 +38,167 @@ func (suite *LocalAffiliateSuite) TestGeneration() {
|
||||
|
||||
suite.Require().NoError(suite.runtime.RegisterController(&clusterctrl.LocalAffiliateController{}))
|
||||
|
||||
nodeIdentity, nonK8sRoutedAddresses, discoveryConfig := suite.createResources()
|
||||
|
||||
machineType := config.NewMachineType()
|
||||
machineType.SetMachineType(machine.TypeWorker)
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, machineType))
|
||||
|
||||
ctest.AssertResource(suite, nodeIdentity.TypedSpec().NodeID, func(r *cluster.Affiliate, asrt *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
asrt.Equal([]string{
|
||||
"172.20.0.2",
|
||||
"10.5.0.1",
|
||||
"192.168.192.168",
|
||||
"2001:123:4567::1",
|
||||
}, slices.Map(spec.Addresses, netip.Addr.String))
|
||||
asrt.Equal("example1", spec.Hostname)
|
||||
asrt.Equal("example1.com", spec.Nodename)
|
||||
asrt.Equal(machine.TypeWorker, spec.MachineType)
|
||||
asrt.Equal("Talos ("+version.Tag+")", spec.OperatingSystem)
|
||||
asrt.Equal(cluster.KubeSpanAffiliateSpec{}, spec.KubeSpan)
|
||||
})
|
||||
|
||||
// enable kubespan
|
||||
mac, err := net.ParseMAC("ea:71:1b:b2:cc:ee")
|
||||
suite.Require().NoError(err)
|
||||
|
||||
ksIdentity := kubespan.NewIdentity(kubespan.NamespaceName, kubespan.LocalIdentity)
|
||||
suite.Require().NoError(kubespanadapter.IdentitySpec(ksIdentity.TypedSpec()).GenerateKey())
|
||||
suite.Require().NoError(kubespanadapter.IdentitySpec(ksIdentity.TypedSpec()).UpdateAddress("8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=", mac))
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, ksIdentity))
|
||||
|
||||
ksConfig := kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID)
|
||||
ksConfig.TypedSpec().EndpointFilters = []string{"0.0.0.0/0", "!192.168.0.0/16", "2001::/16"}
|
||||
ksConfig.TypedSpec().AdvertiseKubernetesNetworks = true
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, ksConfig))
|
||||
|
||||
// add KS address to the list of node addresses, it should be ignored in the endpoints
|
||||
nonK8sRoutedAddresses.TypedSpec().Addresses = append(nonK8sRoutedAddresses.TypedSpec().Addresses, ksIdentity.TypedSpec().Address)
|
||||
suite.Require().NoError(suite.state.Update(suite.ctx, nonK8sRoutedAddresses))
|
||||
|
||||
onlyK8sAddresses := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterOnlyK8s))
|
||||
onlyK8sAddresses.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix("10.244.1.0/24")}
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, onlyK8sAddresses))
|
||||
|
||||
// add discovered public IPs
|
||||
for _, addr := range []netip.Addr{
|
||||
netip.MustParseAddr("1.1.1.1"),
|
||||
netip.MustParseAddr("2001:123:4567::1"), // duplicate, will be ignored
|
||||
} {
|
||||
discoveredAddr := network.NewAddressStatus(cluster.NamespaceName, addr.String())
|
||||
discoveredAddr.TypedSpec().Address = netip.PrefixFrom(addr, addr.BitLen())
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, discoveredAddr))
|
||||
}
|
||||
|
||||
ctest.AssertResource(suite, nodeIdentity.TypedSpec().NodeID, func(r *cluster.Affiliate, asrt *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
asrt.False(len(spec.Addresses) < 5)
|
||||
|
||||
asrt.Equal([]netip.Addr{
|
||||
netip.MustParseAddr("172.20.0.2"),
|
||||
netip.MustParseAddr("10.5.0.1"),
|
||||
netip.MustParseAddr("192.168.192.168"),
|
||||
netip.MustParseAddr("2001:123:4567::1"),
|
||||
ksIdentity.TypedSpec().Address.Addr(),
|
||||
}, spec.Addresses)
|
||||
|
||||
asrt.Equal("example1", spec.Hostname)
|
||||
asrt.Equal("example1.com", spec.Nodename)
|
||||
asrt.Equal(machine.TypeWorker, spec.MachineType)
|
||||
|
||||
asrt.NotZero(spec.KubeSpan.PublicKey)
|
||||
asrt.NotZero(spec.KubeSpan.AdditionalAddresses)
|
||||
asrt.Len(spec.KubeSpan.Endpoints, 4)
|
||||
|
||||
asrt.Equal(ksIdentity.TypedSpec().Address.Addr(), spec.KubeSpan.Address)
|
||||
asrt.Equal(ksIdentity.TypedSpec().PublicKey, spec.KubeSpan.PublicKey)
|
||||
asrt.Equal([]netip.Prefix{netip.MustParsePrefix("10.244.1.0/24")}, spec.KubeSpan.AdditionalAddresses)
|
||||
asrt.Equal(
|
||||
[]string{
|
||||
"172.20.0.2:51820",
|
||||
"10.5.0.1:51820",
|
||||
"1.1.1.1:51820",
|
||||
"[2001:123:4567::1]:51820",
|
||||
},
|
||||
slices.Map(spec.KubeSpan.Endpoints, netip.AddrPort.String),
|
||||
)
|
||||
})
|
||||
|
||||
// disable advertising K8s addresses
|
||||
ksConfig.TypedSpec().AdvertiseKubernetesNetworks = false
|
||||
suite.Require().NoError(suite.state.Update(suite.ctx, ksConfig))
|
||||
|
||||
ctest.AssertResource(suite, nodeIdentity.TypedSpec().NodeID, func(r *cluster.Affiliate, asrt *assert.Assertions) {
|
||||
asrt.Empty(r.TypedSpec().KubeSpan.AdditionalAddresses)
|
||||
})
|
||||
|
||||
// disable discovery, local affiliate should be removed
|
||||
discoveryConfig.TypedSpec().DiscoveryEnabled = false
|
||||
suite.Require().NoError(suite.state.Update(suite.ctx, discoveryConfig))
|
||||
|
||||
ctest.AssertNoResource[*cluster.Affiliate](suite, nodeIdentity.TypedSpec().NodeID)
|
||||
}
|
||||
|
||||
func (suite *LocalAffiliateSuite) TestCPGeneration() {
|
||||
suite.startRuntime()
|
||||
|
||||
suite.Require().NoError(suite.runtime.RegisterController(&clusterctrl.LocalAffiliateController{}))
|
||||
|
||||
nodeIdentity, _, discoveryConfig := suite.createResources()
|
||||
|
||||
machineType := config.NewMachineType()
|
||||
machineType.SetMachineType(machine.TypeControlPlane)
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, machineType))
|
||||
|
||||
u, err := url.Parse("https://foo:6443")
|
||||
suite.Require().NoError(err)
|
||||
|
||||
mc := config.NewMachineConfig(
|
||||
container.NewV1Alpha1(
|
||||
&v1alpha1.Config{
|
||||
ConfigVersion: "v1alpha1",
|
||||
MachineConfig: &v1alpha1.MachineConfig{},
|
||||
ClusterConfig: &v1alpha1.ClusterConfig{
|
||||
ControlPlane: &v1alpha1.ControlPlaneConfig{
|
||||
Endpoint: &v1alpha1.Endpoint{
|
||||
URL: u,
|
||||
},
|
||||
LocalAPIServerPort: 6445,
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, mc))
|
||||
|
||||
ctest.AssertResource(suite, nodeIdentity.TypedSpec().NodeID, func(r *cluster.Affiliate, asrt *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
asrt.Equal([]string{
|
||||
"172.20.0.2",
|
||||
"10.5.0.1",
|
||||
"192.168.192.168",
|
||||
"2001:123:4567::1",
|
||||
}, slices.Map(spec.Addresses, netip.Addr.String))
|
||||
asrt.Equal("example1", spec.Hostname)
|
||||
asrt.Equal("example1.com", spec.Nodename)
|
||||
asrt.Equal(machine.TypeControlPlane, spec.MachineType)
|
||||
asrt.Equal("Talos ("+version.Tag+")", spec.OperatingSystem)
|
||||
asrt.Equal(cluster.KubeSpanAffiliateSpec{}, spec.KubeSpan)
|
||||
asrt.NotNil(spec.ControlPlane)
|
||||
asrt.Equal(6445, spec.ControlPlane.APIServerPort)
|
||||
})
|
||||
|
||||
discoveryConfig.TypedSpec().DiscoveryEnabled = false
|
||||
suite.Require().NoError(suite.state.Update(suite.ctx, discoveryConfig))
|
||||
|
||||
ctest.AssertNoResource[*cluster.Affiliate](suite, nodeIdentity.TypedSpec().NodeID)
|
||||
}
|
||||
|
||||
func (suite *LocalAffiliateSuite) createResources() (*cluster.Identity, *network.NodeAddress, *cluster.Config) {
|
||||
// regular discovery affiliate
|
||||
discoveryConfig := cluster.NewConfig(config.NamespaceName, cluster.ConfigID)
|
||||
discoveryConfig.TypedSpec().DiscoveryEnabled = true
|
||||
@ -73,133 +237,7 @@ func (suite *LocalAffiliateSuite) TestGeneration() {
|
||||
}
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, nonK8sRoutedAddresses))
|
||||
|
||||
machineType := config.NewMachineType()
|
||||
machineType.SetMachineType(machine.TypeWorker)
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, machineType))
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewAffiliate(cluster.NamespaceName, nodeIdentity.TypedSpec().NodeID).Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Affiliate).TypedSpec()
|
||||
|
||||
suite.Assert().Equal([]netip.Addr{
|
||||
netip.MustParseAddr("172.20.0.2"),
|
||||
netip.MustParseAddr("10.5.0.1"),
|
||||
netip.MustParseAddr("192.168.192.168"),
|
||||
netip.MustParseAddr("2001:123:4567::1"),
|
||||
}, spec.Addresses)
|
||||
suite.Assert().Equal("example1", spec.Hostname)
|
||||
suite.Assert().Equal("example1.com", spec.Nodename)
|
||||
suite.Assert().Equal(machine.TypeWorker, spec.MachineType)
|
||||
suite.Assert().Equal("Talos ("+version.Tag+")", spec.OperatingSystem)
|
||||
suite.Assert().Equal(cluster.KubeSpanAffiliateSpec{}, spec.KubeSpan)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
|
||||
// enable kubespan
|
||||
mac, err := net.ParseMAC("ea:71:1b:b2:cc:ee")
|
||||
suite.Require().NoError(err)
|
||||
|
||||
ksIdentity := kubespan.NewIdentity(kubespan.NamespaceName, kubespan.LocalIdentity)
|
||||
suite.Require().NoError(kubespanadapter.IdentitySpec(ksIdentity.TypedSpec()).GenerateKey())
|
||||
suite.Require().NoError(kubespanadapter.IdentitySpec(ksIdentity.TypedSpec()).UpdateAddress("8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=", mac))
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, ksIdentity))
|
||||
|
||||
ksConfig := kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID)
|
||||
ksConfig.TypedSpec().EndpointFilters = []string{"0.0.0.0/0", "!192.168.0.0/16", "2001::/16"}
|
||||
ksConfig.TypedSpec().AdvertiseKubernetesNetworks = true
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, ksConfig))
|
||||
|
||||
// add KS address to the list of node addresses, it should be ignored in the endpoints
|
||||
nonK8sRoutedAddresses.TypedSpec().Addresses = append(nonK8sRoutedAddresses.TypedSpec().Addresses, ksIdentity.TypedSpec().Address)
|
||||
suite.Require().NoError(suite.state.Update(suite.ctx, nonK8sRoutedAddresses))
|
||||
|
||||
onlyK8sAddresses := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterOnlyK8s))
|
||||
onlyK8sAddresses.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix("10.244.1.0/24")}
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, onlyK8sAddresses))
|
||||
|
||||
// add discovered public IPs
|
||||
for _, addr := range []netip.Addr{
|
||||
netip.MustParseAddr("1.1.1.1"),
|
||||
netip.MustParseAddr("2001:123:4567::1"), // duplicate, will be ignored
|
||||
} {
|
||||
discoveredAddr := network.NewAddressStatus(cluster.NamespaceName, addr.String())
|
||||
discoveredAddr.TypedSpec().Address = netip.PrefixFrom(addr, addr.BitLen())
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, discoveredAddr))
|
||||
}
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewAffiliate(cluster.NamespaceName, nodeIdentity.TypedSpec().NodeID).Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Affiliate).TypedSpec()
|
||||
|
||||
if len(spec.Addresses) < 5 {
|
||||
return retry.ExpectedErrorf("not reconciled yet")
|
||||
}
|
||||
|
||||
suite.Assert().Equal([]netip.Addr{
|
||||
netip.MustParseAddr("172.20.0.2"),
|
||||
netip.MustParseAddr("10.5.0.1"),
|
||||
netip.MustParseAddr("192.168.192.168"),
|
||||
netip.MustParseAddr("2001:123:4567::1"),
|
||||
ksIdentity.TypedSpec().Address.Addr(),
|
||||
}, spec.Addresses)
|
||||
|
||||
suite.Assert().Equal("example1", spec.Hostname)
|
||||
suite.Assert().Equal("example1.com", spec.Nodename)
|
||||
suite.Assert().Equal(machine.TypeWorker, spec.MachineType)
|
||||
|
||||
if spec.KubeSpan.PublicKey == "" {
|
||||
return retry.ExpectedErrorf("kubespan is not filled in yet")
|
||||
}
|
||||
|
||||
if spec.KubeSpan.AdditionalAddresses == nil {
|
||||
return retry.ExpectedErrorf("kubespan is not filled in yet")
|
||||
}
|
||||
|
||||
if len(spec.KubeSpan.Endpoints) != 4 {
|
||||
return retry.ExpectedErrorf("kubespan endpoints are not reconciled yet")
|
||||
}
|
||||
|
||||
suite.Assert().Equal(ksIdentity.TypedSpec().Address.Addr(), spec.KubeSpan.Address)
|
||||
suite.Assert().Equal(ksIdentity.TypedSpec().PublicKey, spec.KubeSpan.PublicKey)
|
||||
suite.Assert().Equal([]netip.Prefix{netip.MustParsePrefix("10.244.1.0/24")}, spec.KubeSpan.AdditionalAddresses)
|
||||
suite.Assert().Equal([]netip.AddrPort{
|
||||
netip.MustParseAddrPort("172.20.0.2:51820"),
|
||||
netip.MustParseAddrPort("10.5.0.1:51820"),
|
||||
netip.MustParseAddrPort("1.1.1.1:51820"),
|
||||
netip.MustParseAddrPort("[2001:123:4567::1]:51820"),
|
||||
}, spec.KubeSpan.Endpoints)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
|
||||
// disable advertising K8s addresses
|
||||
ksConfig.TypedSpec().AdvertiseKubernetesNetworks = false
|
||||
suite.Require().NoError(suite.state.Update(suite.ctx, ksConfig))
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewAffiliate(cluster.NamespaceName, nodeIdentity.TypedSpec().NodeID).Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Affiliate).TypedSpec()
|
||||
|
||||
if spec.KubeSpan.AdditionalAddresses != nil {
|
||||
return retry.ExpectedErrorf("additional addresses are not cleared yet")
|
||||
}
|
||||
|
||||
suite.Assert().Empty(spec.KubeSpan.AdditionalAddresses)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
|
||||
// disable discovery, local affiliate should be removed
|
||||
discoveryConfig.TypedSpec().DiscoveryEnabled = false
|
||||
suite.Require().NoError(suite.state.Update(suite.ctx, discoveryConfig))
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertNoResource(*cluster.NewAffiliate(cluster.NamespaceName, nodeIdentity.TypedSpec().NodeID).Metadata()),
|
||||
))
|
||||
return nodeIdentity, nonK8sRoutedAddresses, discoveryConfig
|
||||
}
|
||||
|
||||
func TestLocalAffiliateSuite(t *testing.T) {
|
||||
|
||||
@ -10,6 +10,8 @@ import (
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/controller"
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
"github.com/siderolabs/gen/channel"
|
||||
"github.com/siderolabs/gen/slices"
|
||||
"go.uber.org/zap"
|
||||
|
||||
@ -48,36 +50,35 @@ func (ctrl *MemberController) Outputs() []controller.Output {
|
||||
// Run implements controller.Controller interface.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (ctrl *MemberController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
func (ctrl *MemberController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-r.EventCh():
|
||||
if _, ok := channel.RecvWithContext(ctx, r.EventCh()); !ok && ctx.Err() != nil {
|
||||
return nil //nolint:nilerr
|
||||
}
|
||||
|
||||
affiliates, err := r.List(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.AffiliateType, "", resource.VersionUndefined))
|
||||
affiliates, err := safe.ReaderListAll[*cluster.Affiliate](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing affiliates")
|
||||
}
|
||||
|
||||
touchedIDs := make(map[resource.ID]struct{})
|
||||
|
||||
for _, affiliate := range affiliates.Items {
|
||||
affiliateSpec := affiliate.(*cluster.Affiliate).TypedSpec()
|
||||
for it := safe.IteratorFromList(affiliates); it.Next(); {
|
||||
affiliateSpec := it.Value().TypedSpec()
|
||||
if affiliateSpec.Nodename == "" {
|
||||
// not a cluster member
|
||||
continue
|
||||
}
|
||||
|
||||
if err = r.Modify(ctx, cluster.NewMember(cluster.NamespaceName, affiliateSpec.Nodename), func(res resource.Resource) error {
|
||||
spec := res.(*cluster.Member).TypedSpec()
|
||||
if err = safe.WriterModify(ctx, r, cluster.NewMember(cluster.NamespaceName, affiliateSpec.Nodename), func(res *cluster.Member) error {
|
||||
spec := res.TypedSpec()
|
||||
|
||||
spec.Addresses = slices.Clone(affiliateSpec.Addresses)
|
||||
spec.Hostname = affiliateSpec.Hostname
|
||||
spec.MachineType = affiliateSpec.MachineType
|
||||
spec.OperatingSystem = affiliateSpec.OperatingSystem
|
||||
spec.NodeID = affiliateSpec.NodeID
|
||||
spec.ControlPlane = affiliateSpec.ControlPlane
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -88,12 +89,14 @@ func (ctrl *MemberController) Run(ctx context.Context, r controller.Runtime, log
|
||||
}
|
||||
|
||||
// list keys for cleanup
|
||||
list, err := r.List(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.MemberType, "", resource.VersionUndefined))
|
||||
list, err := safe.ReaderListAll[*cluster.Member](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing resources: %w", err)
|
||||
}
|
||||
|
||||
for _, res := range list.Items {
|
||||
for it := safe.IteratorFromList(list); it.Next(); {
|
||||
res := it.Value()
|
||||
|
||||
if res.Metadata().Owner() != ctrl.Name() {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -7,13 +7,13 @@ package cluster_test
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/siderolabs/go-retry/retry"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
|
||||
)
|
||||
@ -41,6 +41,7 @@ func (suite *MemberSuite) TestReconcileDefault() {
|
||||
AdditionalAddresses: []netip.Prefix{netip.MustParsePrefix("10.244.3.1/24")},
|
||||
Endpoints: []netip.AddrPort{netip.MustParseAddrPort("10.0.0.2:51820"), netip.MustParseAddrPort("192.168.3.4:51820")},
|
||||
},
|
||||
ControlPlane: &cluster.ControlPlane{APIServerPort: 6443},
|
||||
}
|
||||
|
||||
affiliate2 := cluster.NewAffiliate(cluster.NamespaceName, "9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F")
|
||||
@ -64,39 +65,38 @@ func (suite *MemberSuite) TestReconcileDefault() {
|
||||
}
|
||||
|
||||
// affiliates with non-empty Nodename should be translated to Members
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewMember(cluster.NamespaceName, affiliate1.TypedSpec().Nodename).Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Member).TypedSpec()
|
||||
ctest.AssertResource(
|
||||
suite,
|
||||
affiliate1.TypedSpec().Nodename,
|
||||
func(r *cluster.Member, asrt *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
suite.Assert().Equal(affiliate1.TypedSpec().NodeID, spec.NodeID)
|
||||
suite.Assert().Equal([]netip.Addr{netip.MustParseAddr("192.168.3.4")}, spec.Addresses)
|
||||
suite.Assert().Equal("foo.com", spec.Hostname)
|
||||
suite.Assert().Equal(machine.TypeControlPlane, spec.MachineType)
|
||||
suite.Assert().Equal("Talos (v1.0.0)", spec.OperatingSystem)
|
||||
asrt.Equal(affiliate1.TypedSpec().NodeID, spec.NodeID)
|
||||
asrt.Equal([]netip.Addr{netip.MustParseAddr("192.168.3.4")}, spec.Addresses)
|
||||
asrt.Equal("foo.com", spec.Hostname)
|
||||
asrt.Equal(machine.TypeControlPlane, spec.MachineType)
|
||||
asrt.Equal("Talos (v1.0.0)", spec.OperatingSystem)
|
||||
asrt.Equal(6443, spec.ControlPlane.APIServerPort)
|
||||
},
|
||||
)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
ctest.AssertResource(
|
||||
suite,
|
||||
affiliate2.TypedSpec().Nodename,
|
||||
func(r *cluster.Member, asrt *assert.Assertions) {
|
||||
spec := r.TypedSpec()
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertResource(*cluster.NewMember(cluster.NamespaceName, affiliate2.TypedSpec().Nodename).Metadata(), func(r resource.Resource) error {
|
||||
spec := r.(*cluster.Member).TypedSpec()
|
||||
|
||||
suite.Assert().Equal(affiliate2.TypedSpec().NodeID, spec.NodeID)
|
||||
suite.Assert().Equal([]netip.Addr{netip.MustParseAddr("192.168.3.5")}, spec.Addresses)
|
||||
suite.Assert().Equal("worker-1", spec.Hostname)
|
||||
suite.Assert().Equal(machine.TypeWorker, spec.MachineType)
|
||||
|
||||
return nil
|
||||
}),
|
||||
))
|
||||
asrt.Equal(affiliate2.TypedSpec().NodeID, spec.NodeID)
|
||||
asrt.Equal([]netip.Addr{netip.MustParseAddr("192.168.3.5")}, spec.Addresses)
|
||||
asrt.Equal("worker-1", spec.Hostname)
|
||||
asrt.Equal(machine.TypeWorker, spec.MachineType)
|
||||
},
|
||||
)
|
||||
|
||||
// remove affiliate2, member information should eventually go away
|
||||
suite.Require().NoError(suite.state.Destroy(suite.ctx, affiliate2.Metadata()))
|
||||
|
||||
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
suite.assertNoResource(*cluster.NewMember(cluster.NamespaceName, affiliate2.TypedSpec().Nodename).Metadata()),
|
||||
))
|
||||
ctest.AssertNoResource[*cluster.Member](suite, affiliate2.TypedSpec().Nodename)
|
||||
}
|
||||
|
||||
func TestMemberSuite(t *testing.T) {
|
||||
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"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/go-pointer"
|
||||
@ -60,7 +59,7 @@ func (ctrl *SeccompProfileController) Run(ctx context.Context, r controller.Runt
|
||||
case <-r.EventCh():
|
||||
}
|
||||
|
||||
cfg, err := safe.ReaderGet[*config.MachineConfig](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
|
||||
cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
continue
|
||||
|
||||
@ -14,11 +14,13 @@ import (
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/controller/runtime"
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/resource/rtestutils"
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
"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/go-retry/retry"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
@ -108,6 +110,11 @@ func (suite *DefaultSuite) TearDownTest() {
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates a new resource in the state of the suite.
|
||||
func (suite *DefaultSuite) Create(res resource.Resource, opts ...state.CreateOption) {
|
||||
suite.Require().NoError(suite.State().Create(suite.Ctx(), res, opts...))
|
||||
}
|
||||
|
||||
// Suite is a type which describes the suite type.
|
||||
type Suite interface {
|
||||
T() *testing.T
|
||||
@ -134,3 +141,51 @@ func GetUsingResource[T resource.Resource](suite Suite, res T, options ...state.
|
||||
func Get[T resource.Resource](suite Suite, ptr resource.Pointer, options ...state.GetOption) (T, error) { //nolint:ireturn
|
||||
return safe.StateGet[T](suite.Ctx(), suite.State(), ptr, options...)
|
||||
}
|
||||
|
||||
// Suiter is like Suite but do not require Require() method.
|
||||
type Suiter interface {
|
||||
T() *testing.T
|
||||
State() state.State
|
||||
Ctx() context.Context
|
||||
}
|
||||
|
||||
// AssertResources asserts on a resource list.
|
||||
func AssertResources[R rtestutils.ResourceWithRD](
|
||||
suiter Suiter,
|
||||
requiredIDs []resource.ID,
|
||||
check func(R, *assert.Assertions),
|
||||
opts ...rtestutils.Option,
|
||||
) {
|
||||
ctx, cancel := context.WithTimeout(suiter.Ctx(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
rtestutils.AssertResources(ctx, suiter.T(), suiter.State(), requiredIDs, check, opts...)
|
||||
}
|
||||
|
||||
// AssertResource asserts on a single resource.
|
||||
func AssertResource[R rtestutils.ResourceWithRD](
|
||||
suiter Suiter,
|
||||
requiredIDs resource.ID,
|
||||
check func(R, *assert.Assertions),
|
||||
opts ...rtestutils.Option,
|
||||
) {
|
||||
AssertResources(suiter, []resource.ID{requiredIDs}, check, opts...)
|
||||
}
|
||||
|
||||
// AssertNoResource asserts that a resource no longer exists.
|
||||
func AssertNoResource[R rtestutils.ResourceWithRD](
|
||||
suiter Suiter,
|
||||
id string,
|
||||
opts ...rtestutils.Option,
|
||||
) {
|
||||
ctx, cancel := context.WithTimeout(suiter.Ctx(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
rtestutils.AssertNoResource[R](
|
||||
ctx,
|
||||
suiter.T(),
|
||||
suiter.State(),
|
||||
id,
|
||||
opts...,
|
||||
)
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ func (ctrl *ConfigController) Run(ctx context.Context, r controller.Runtime, log
|
||||
continue
|
||||
}
|
||||
|
||||
machineConfig, err := safe.ReaderGet[*config.MachineConfig](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
|
||||
machineConfig, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
continue
|
||||
|
||||
170
internal/app/machined/pkg/controllers/k8s/apiserver_endpoints.go
Normal file
170
internal/app/machined/pkg/controllers/k8s/apiserver_endpoints.go
Normal file
@ -0,0 +1,170 @@
|
||||
// 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 k8s
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"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/channel"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/config"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/k8s"
|
||||
)
|
||||
|
||||
// APIServerEndpointsController creates a list of API server endpoints.
|
||||
type APIServerEndpointsController struct{}
|
||||
|
||||
// Name implements controller.Controller interface.
|
||||
func (ctrl *APIServerEndpointsController) Name() string {
|
||||
return "cluster.APIServerEndpointsController"
|
||||
}
|
||||
|
||||
// Inputs implements controller.Controller interface.
|
||||
func (ctrl *APIServerEndpointsController) Inputs() []controller.Input {
|
||||
return []controller.Input{
|
||||
{
|
||||
Namespace: config.NamespaceName,
|
||||
Type: config.MachineTypeType,
|
||||
ID: pointer.To(config.MachineTypeID),
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
safe.Input[*cluster.Member](controller.InputWeak),
|
||||
safe.Input[*config.MachineConfig](controller.InputWeak),
|
||||
}
|
||||
}
|
||||
|
||||
// Outputs implements controller.Controller interface.
|
||||
func (ctrl *APIServerEndpointsController) Outputs() []controller.Output {
|
||||
return []controller.Output{
|
||||
{
|
||||
Type: k8s.APIServerEndpointsType,
|
||||
Kind: controller.OutputExclusive,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Run implements controller.Controller interface.
|
||||
//
|
||||
//nolint:gocyclo,cyclop
|
||||
func (ctrl *APIServerEndpointsController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
for {
|
||||
if _, ok := channel.RecvWithContext(ctx, r.EventCh()); !ok && ctx.Err() != nil {
|
||||
return nil //nolint:nilerr
|
||||
}
|
||||
|
||||
machineConfig, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting machine config: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
machineType, err := safe.ReaderGetByID[*config.MachineType](ctx, r, config.MachineTypeID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting machine type: %w", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
members, err := safe.ReaderListAll[*cluster.Member](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing affiliates: %w", err)
|
||||
}
|
||||
|
||||
var endpoints []k8s.APIServerEndpoint
|
||||
|
||||
ce := machineConfig.Config().Cluster().Endpoint()
|
||||
if ce != nil {
|
||||
endpoints = append(endpoints, k8s.APIServerEndpoint{
|
||||
Host: ce.Hostname(),
|
||||
Port: toPort(ce.Port()),
|
||||
})
|
||||
}
|
||||
|
||||
if machineType.MachineType() == machine.TypeControlPlane {
|
||||
endpoints = append(endpoints, k8s.APIServerEndpoint{
|
||||
Host: "localhost",
|
||||
Port: uint32(machineConfig.Config().Cluster().LocalAPIServerPort()),
|
||||
})
|
||||
}
|
||||
|
||||
for it := safe.IteratorFromList(members); it.Next(); {
|
||||
memberSpec := it.Value().TypedSpec()
|
||||
|
||||
if len(memberSpec.Addresses) > 0 && memberSpec.ControlPlane != nil {
|
||||
for _, addr := range memberSpec.Addresses {
|
||||
endpoints = append(endpoints, k8s.APIServerEndpoint{
|
||||
Host: addr.String(),
|
||||
Port: uint32(memberSpec.ControlPlane.APIServerPort),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = safe.WriterModify[*k8s.APIServerEndpoints](
|
||||
ctx,
|
||||
r,
|
||||
k8s.NewEndpoints(k8s.NamespaceName, k8s.APIServerEndpointsID),
|
||||
func(res *k8s.APIServerEndpoints) error {
|
||||
res.TypedSpec().Endpoints = endpoints
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating endpoints: %w", err)
|
||||
}
|
||||
|
||||
// list keys for cleanup
|
||||
list, err := safe.ReaderListAll[*k8s.APIServerEndpoints](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing resources: %w", err)
|
||||
}
|
||||
|
||||
for it := safe.IteratorFromList(list); it.Next(); {
|
||||
res := it.Value()
|
||||
|
||||
if res.Metadata().Owner() != ctrl.Name() {
|
||||
continue
|
||||
}
|
||||
|
||||
if res.Metadata().ID() != k8s.APIServerEndpointsID {
|
||||
if err = r.Destroy(ctx, res.Metadata()); err != nil {
|
||||
return fmt.Errorf("error cleaning up specs: %w", err)
|
||||
}
|
||||
|
||||
logger.Info("removed endpoints resource", zap.String("id", res.Metadata().ID()))
|
||||
}
|
||||
}
|
||||
|
||||
r.ResetRestartBackoff()
|
||||
}
|
||||
}
|
||||
|
||||
func toPort(port string) uint32 {
|
||||
if port == "" {
|
||||
return 443
|
||||
}
|
||||
|
||||
p, err := strconv.ParseUint(port, 10, 32)
|
||||
if err != nil {
|
||||
return 443
|
||||
}
|
||||
|
||||
return uint32(p)
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
// 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 k8s_test
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
clusteradapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest"
|
||||
clusterctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/container"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/config"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/k8s"
|
||||
)
|
||||
|
||||
type EndpointsBalancerControllerSuite struct {
|
||||
ctest.DefaultSuite
|
||||
}
|
||||
|
||||
func (suite *EndpointsBalancerControllerSuite) TestGeneration() {
|
||||
nodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity)
|
||||
suite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate())
|
||||
suite.Create(nodeIdentity)
|
||||
|
||||
mc := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{
|
||||
ConfigVersion: "v1alpha1",
|
||||
MachineConfig: &v1alpha1.MachineConfig{},
|
||||
ClusterConfig: &v1alpha1.ClusterConfig{
|
||||
ControlPlane: &v1alpha1.ControlPlaneConfig{
|
||||
Endpoint: &v1alpha1.Endpoint{
|
||||
URL: must(url.Parse("https://example.com"))(suite.Require()),
|
||||
},
|
||||
LocalAPIServerPort: 6445,
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
suite.Create(mc)
|
||||
|
||||
machineType := config.NewMachineType()
|
||||
machineType.SetMachineType(machine.TypeControlPlane)
|
||||
suite.Create(machineType)
|
||||
|
||||
member1 := cluster.NewMember(cluster.NamespaceName, "service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC")
|
||||
*member1.TypedSpec() = cluster.MemberSpec{
|
||||
NodeID: "7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC",
|
||||
Hostname: "foo.com",
|
||||
MachineType: machine.TypeControlPlane,
|
||||
Addresses: []netip.Addr{netip.MustParseAddr("192.168.3.4")},
|
||||
ControlPlane: &cluster.ControlPlane{APIServerPort: 6446},
|
||||
}
|
||||
|
||||
suite.Create(member1)
|
||||
|
||||
member2 := cluster.NewMember(cluster.NamespaceName, "service/xCnFFfxylOf9i5ynhAkt6ZbfcqaLDGKfIa3gwpuaxe7F")
|
||||
*member2.TypedSpec() = cluster.MemberSpec{
|
||||
NodeID: nodeIdentity.TypedSpec().NodeID,
|
||||
Hostname: "foo2.com",
|
||||
MachineType: machine.TypeControlPlane,
|
||||
Addresses: []netip.Addr{netip.MustParseAddr("192.168.3.6")},
|
||||
ControlPlane: &cluster.ControlPlane{APIServerPort: 6443},
|
||||
}
|
||||
|
||||
suite.Create(member2)
|
||||
|
||||
member3 := cluster.NewMember(cluster.NamespaceName, "service/9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F")
|
||||
*member3.TypedSpec() = cluster.MemberSpec{
|
||||
NodeID: "9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F",
|
||||
Hostname: "worker-1",
|
||||
MachineType: machine.TypeWorker,
|
||||
Addresses: []netip.Addr{netip.MustParseAddr("192.168.3.5")},
|
||||
}
|
||||
|
||||
suite.Create(member3)
|
||||
|
||||
ctest.AssertResource(suite, k8s.APIServerEndpointsID, func(e *k8s.APIServerEndpoints, asrt *assert.Assertions) {
|
||||
asrt.Equal(
|
||||
&k8s.APIServerEndpointsSpec{
|
||||
Endpoints: []k8s.APIServerEndpoint{
|
||||
{
|
||||
Host: "example.com",
|
||||
Port: 443,
|
||||
},
|
||||
{
|
||||
Host: "localhost",
|
||||
Port: 6445,
|
||||
},
|
||||
{
|
||||
Host: "192.168.3.4",
|
||||
Port: 6446,
|
||||
},
|
||||
{
|
||||
Host: "192.168.3.6",
|
||||
Port: 6443,
|
||||
},
|
||||
},
|
||||
},
|
||||
e.TypedSpec(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
func must[T any](res T, err error) func(t *require.Assertions) T {
|
||||
return func(t *require.Assertions) T {
|
||||
t.NoError(err)
|
||||
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
func TestEndpointsBalancerControllerSuite(t *testing.T) {
|
||||
suite.Run(t, &EndpointsBalancerControllerSuite{
|
||||
DefaultSuite: ctest.DefaultSuite{
|
||||
AfterSetup: func(suite *ctest.DefaultSuite) {
|
||||
suite.Require().NoError(suite.Runtime().RegisterController(&clusterctrl.APIServerEndpointsController{}))
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -97,7 +97,7 @@ func (ctrl *ControlPlaneController) Run(ctx context.Context, r controller.Runtim
|
||||
case <-r.EventCh():
|
||||
}
|
||||
|
||||
cfg, err := safe.ReaderGet[*config.MachineConfig](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
|
||||
cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
if err = ctrl.teardownAll(ctx, r); err != nil {
|
||||
|
||||
@ -78,7 +78,7 @@ func (ctrl *KubeletConfigController) Run(ctx context.Context, r controller.Runti
|
||||
return fmt.Errorf("error accessing static pod server status resource: %w", err)
|
||||
}
|
||||
|
||||
cfg, err := safe.ReaderGet[*config.MachineConfig](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
|
||||
cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
continue
|
||||
|
||||
@ -9,7 +9,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"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/go-pointer"
|
||||
@ -62,7 +61,7 @@ func (ctrl *NodeLabelSpecController) Run(ctx context.Context, r controller.Runti
|
||||
|
||||
var nodeLabels map[string]string
|
||||
|
||||
cfg, err := safe.ReaderGet[*config.MachineConfig](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
|
||||
cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting config: %w", err)
|
||||
|
||||
@ -11,7 +11,6 @@ import (
|
||||
"net/netip"
|
||||
|
||||
"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/slices"
|
||||
@ -61,7 +60,7 @@ func (ctrl *StaticEndpointController) Run(ctx context.Context, r controller.Runt
|
||||
case <-r.EventCh():
|
||||
}
|
||||
|
||||
machineConfig, err := safe.ReaderGet[*config.MachineConfig](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
|
||||
machineConfig, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
continue
|
||||
|
||||
@ -10,6 +10,8 @@ import (
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/controller"
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
"github.com/siderolabs/gen/channel"
|
||||
"github.com/siderolabs/gen/value"
|
||||
"go.uber.org/zap"
|
||||
|
||||
@ -56,18 +58,16 @@ func (ctrl *EndpointController) Outputs() []controller.Output {
|
||||
//nolint:gocyclo
|
||||
func (ctrl *EndpointController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-r.EventCh():
|
||||
if _, ok := channel.RecvWithContext(ctx, r.EventCh()); !ok && ctx.Err() != nil {
|
||||
return nil //nolint:nilerr
|
||||
}
|
||||
|
||||
peerStatuses, err := r.List(ctx, resource.NewMetadata(kubespan.NamespaceName, kubespan.PeerStatusType, "", resource.VersionUndefined))
|
||||
peerStatuses, err := safe.ReaderListAll[*kubespan.PeerStatus](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing cluster affiliates: %w", err)
|
||||
}
|
||||
|
||||
affiliates, err := r.List(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.AffiliateType, "", resource.VersionUndefined))
|
||||
affiliates, err := safe.ReaderListAll[*cluster.Affiliate](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing cluster affiliates: %w", err)
|
||||
}
|
||||
@ -75,8 +75,8 @@ func (ctrl *EndpointController) Run(ctx context.Context, r controller.Runtime, l
|
||||
// build lookup table of affiliate's kubespan public key back to affiliate ID
|
||||
affiliateLookup := make(map[string]string)
|
||||
|
||||
for _, res := range affiliates.Items {
|
||||
affiliate := res.(*cluster.Affiliate).TypedSpec()
|
||||
for it := safe.IteratorFromList(affiliates); it.Next(); {
|
||||
affiliate := it.Value().TypedSpec()
|
||||
|
||||
if affiliate.KubeSpan.PublicKey != "" {
|
||||
affiliateLookup[affiliate.KubeSpan.PublicKey] = affiliate.NodeID
|
||||
@ -86,8 +86,9 @@ func (ctrl *EndpointController) Run(ctx context.Context, r controller.Runtime, l
|
||||
// for every kubespan peer, if it's up and has endpoint, harvest that endpoint
|
||||
touchedIDs := make(map[resource.ID]struct{})
|
||||
|
||||
for _, res := range peerStatuses.Items {
|
||||
peerStatus := res.(*kubespan.PeerStatus).TypedSpec()
|
||||
for it := safe.IteratorFromList(peerStatuses); it.Next(); {
|
||||
res := it.Value()
|
||||
peerStatus := res.TypedSpec()
|
||||
|
||||
if peerStatus.State != kubespan.PeerStateUp {
|
||||
continue
|
||||
@ -102,8 +103,8 @@ func (ctrl *EndpointController) Run(ctx context.Context, r controller.Runtime, l
|
||||
continue
|
||||
}
|
||||
|
||||
if err = r.Modify(ctx, kubespan.NewEndpoint(kubespan.NamespaceName, res.Metadata().ID()), func(res resource.Resource) error {
|
||||
*res.(*kubespan.Endpoint).TypedSpec() = kubespan.EndpointSpec{
|
||||
if err = safe.WriterModify(ctx, r, kubespan.NewEndpoint(kubespan.NamespaceName, res.Metadata().ID()), func(res *kubespan.Endpoint) error {
|
||||
*res.TypedSpec() = kubespan.EndpointSpec{
|
||||
AffiliateID: affiliateID,
|
||||
Endpoint: peerStatus.Endpoint,
|
||||
}
|
||||
@ -117,12 +118,14 @@ func (ctrl *EndpointController) Run(ctx context.Context, r controller.Runtime, l
|
||||
}
|
||||
|
||||
// list keys for cleanup
|
||||
list, err := r.List(ctx, resource.NewMetadata(kubespan.NamespaceName, kubespan.EndpointType, "", resource.VersionUndefined))
|
||||
list, err := safe.ReaderListAll[*kubespan.Endpoint](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing resources: %w", err)
|
||||
}
|
||||
|
||||
for _, res := range list.Items {
|
||||
for it := safe.IteratorFromList(list); it.Next(); {
|
||||
res := it.Value()
|
||||
|
||||
if res.Metadata().Owner() != ctrl.Name() {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -10,7 +10,9 @@ import (
|
||||
|
||||
"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/channel"
|
||||
"github.com/siderolabs/gen/slices"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"go.uber.org/zap"
|
||||
@ -67,128 +69,131 @@ func (ctrl *PeerSpecController) Outputs() []controller.Output {
|
||||
//nolint:gocyclo,cyclop
|
||||
func (ctrl *PeerSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-r.EventCh():
|
||||
cfg, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, kubespan.ConfigType, kubespan.ConfigID, resource.VersionUndefined))
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting kubespan configuration: %w", err)
|
||||
}
|
||||
if _, ok := channel.RecvWithContext(ctx, r.EventCh()); !ok && ctx.Err() != nil {
|
||||
return nil //nolint:nilerr
|
||||
}
|
||||
|
||||
localIdentity, err := r.Get(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.IdentityType, cluster.LocalIdentity, resource.VersionUndefined))
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting first MAC address: %w", err)
|
||||
}
|
||||
cfg, err := safe.ReaderGetByID[*kubespan.Config](ctx, r, kubespan.ConfigID)
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting kubespan configuration: %w", err)
|
||||
}
|
||||
|
||||
affiliates, err := r.List(ctx, resource.NewMetadata(cluster.NamespaceName, cluster.AffiliateType, "", resource.VersionUndefined))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing cluster affiliates: %w", err)
|
||||
}
|
||||
localIdentity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting first MAC address: %w", err)
|
||||
}
|
||||
|
||||
touchedIDs := make(map[resource.ID]struct{})
|
||||
affiliates, err := safe.ReaderListAll[*cluster.Affiliate](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing cluster affiliates: %w", err)
|
||||
}
|
||||
|
||||
if cfg != nil && localIdentity != nil && cfg.(*kubespan.Config).TypedSpec().Enabled {
|
||||
localAffiliateID := localIdentity.(*cluster.Identity).TypedSpec().NodeID
|
||||
touchedIDs := map[resource.ID]struct{}{}
|
||||
|
||||
peerIPSets := make(map[string]*netipx.IPSet, len(affiliates.Items))
|
||||
if cfg != nil && localIdentity != nil && cfg.TypedSpec().Enabled {
|
||||
localAffiliateID := localIdentity.TypedSpec().NodeID
|
||||
|
||||
affiliateLoop:
|
||||
for _, affiliate := range affiliates.Items {
|
||||
if affiliate.Metadata().ID() == localAffiliateID {
|
||||
// skip local affiliate, it's not a peer
|
||||
continue
|
||||
}
|
||||
peerIPSets := make(map[string]*netipx.IPSet, affiliates.Len())
|
||||
|
||||
spec := affiliate.(*cluster.Affiliate).TypedSpec()
|
||||
affiliateLoop:
|
||||
for it := safe.IteratorFromList(affiliates); it.Next(); {
|
||||
affiliate := it.Value()
|
||||
|
||||
if spec.KubeSpan.PublicKey == "" {
|
||||
// no kubespan information, skip it
|
||||
continue
|
||||
}
|
||||
|
||||
var builder netipx.IPSetBuilder
|
||||
|
||||
for _, ipPrefix := range spec.KubeSpan.AdditionalAddresses {
|
||||
builder.AddPrefix(ipPrefix)
|
||||
}
|
||||
|
||||
for _, ip := range spec.Addresses {
|
||||
builder.Add(ip)
|
||||
}
|
||||
|
||||
builder.Add(spec.KubeSpan.Address)
|
||||
|
||||
var ipSet *netipx.IPSet
|
||||
|
||||
ipSet, err = builder.IPSet()
|
||||
if err != nil {
|
||||
logger.Warn("failed building list of IP ranges for the peer", zap.String("ignored_peer", spec.KubeSpan.PublicKey), zap.String("label", spec.Nodename), zap.Error(err))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
for otherPublicKey, otherIPSet := range peerIPSets {
|
||||
if otherIPSet.Overlaps(ipSet) {
|
||||
logger.Warn("peer address overlap", zap.String("this_peer", spec.KubeSpan.PublicKey), zap.String("other_peer", otherPublicKey),
|
||||
zap.Strings("this_ips", dumpSet(ipSet)), zap.Strings("other_ips", dumpSet(otherIPSet)))
|
||||
|
||||
// exclude overlapping IPs from the ipSet
|
||||
var bldr netipx.IPSetBuilder
|
||||
|
||||
// ipSet = ipSet & ~otherIPSet
|
||||
bldr.AddSet(otherIPSet)
|
||||
bldr.Complement()
|
||||
bldr.Intersect(ipSet)
|
||||
|
||||
ipSet, err = bldr.IPSet()
|
||||
if err != nil {
|
||||
logger.Warn("failed building list of IP ranges for the peer", zap.String("ignored_peer", spec.KubeSpan.PublicKey), zap.String("label", spec.Nodename), zap.Error(err))
|
||||
|
||||
continue affiliateLoop
|
||||
}
|
||||
|
||||
if len(ipSet.Ranges()) == 0 {
|
||||
logger.Warn("conflict resolution removed all ranges", zap.String("this_peer", spec.KubeSpan.PublicKey), zap.String("other_peer", otherPublicKey))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peerIPSets[spec.KubeSpan.PublicKey] = ipSet
|
||||
|
||||
if err = r.Modify(ctx, kubespan.NewPeerSpec(kubespan.NamespaceName, spec.KubeSpan.PublicKey), func(res resource.Resource) error {
|
||||
*res.(*kubespan.PeerSpec).TypedSpec() = kubespan.PeerSpecSpec{
|
||||
Address: spec.KubeSpan.Address,
|
||||
AllowedIPs: ipSet.Prefixes(),
|
||||
Endpoints: slices.Clone(spec.KubeSpan.Endpoints),
|
||||
Label: spec.Nodename,
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
touchedIDs[spec.KubeSpan.PublicKey] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// list keys for cleanup
|
||||
list, err := r.List(ctx, resource.NewMetadata(kubespan.NamespaceName, kubespan.PeerSpecType, "", resource.VersionUndefined))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing resources: %w", err)
|
||||
}
|
||||
|
||||
for _, res := range list.Items {
|
||||
if res.Metadata().Owner() != ctrl.Name() {
|
||||
if affiliate.Metadata().ID() == localAffiliateID {
|
||||
// skip local affiliate, it's not a peer
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := touchedIDs[res.Metadata().ID()]; !ok {
|
||||
if err = r.Destroy(ctx, res.Metadata()); err != nil {
|
||||
return fmt.Errorf("error cleaning up specs: %w", err)
|
||||
spec := affiliate.TypedSpec()
|
||||
|
||||
if spec.KubeSpan.PublicKey == "" {
|
||||
// no kubespan information, skip it
|
||||
continue
|
||||
}
|
||||
|
||||
var builder netipx.IPSetBuilder
|
||||
|
||||
for _, ipPrefix := range spec.KubeSpan.AdditionalAddresses {
|
||||
builder.AddPrefix(ipPrefix)
|
||||
}
|
||||
|
||||
for _, ip := range spec.Addresses {
|
||||
builder.Add(ip)
|
||||
}
|
||||
|
||||
builder.Add(spec.KubeSpan.Address)
|
||||
|
||||
var ipSet *netipx.IPSet
|
||||
|
||||
ipSet, err = builder.IPSet()
|
||||
if err != nil {
|
||||
logger.Warn("failed building list of IP ranges for the peer", zap.String("ignored_peer", spec.KubeSpan.PublicKey), zap.String("label", spec.Nodename), zap.Error(err))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
for otherPublicKey, otherIPSet := range peerIPSets {
|
||||
if otherIPSet.Overlaps(ipSet) {
|
||||
logger.Warn("peer address overlap", zap.String("this_peer", spec.KubeSpan.PublicKey), zap.String("other_peer", otherPublicKey),
|
||||
zap.Strings("this_ips", dumpSet(ipSet)), zap.Strings("other_ips", dumpSet(otherIPSet)))
|
||||
|
||||
// exclude overlapping IPs from the ipSet
|
||||
var bldr netipx.IPSetBuilder
|
||||
|
||||
// ipSet = ipSet & ~otherIPSet
|
||||
bldr.AddSet(otherIPSet)
|
||||
bldr.Complement()
|
||||
bldr.Intersect(ipSet)
|
||||
|
||||
ipSet, err = bldr.IPSet()
|
||||
if err != nil {
|
||||
logger.Warn("failed building list of IP ranges for the peer", zap.String("ignored_peer", spec.KubeSpan.PublicKey), zap.String("label", spec.Nodename), zap.Error(err))
|
||||
|
||||
continue affiliateLoop
|
||||
}
|
||||
|
||||
if len(ipSet.Ranges()) == 0 {
|
||||
logger.Warn("conflict resolution removed all ranges", zap.String("this_peer", spec.KubeSpan.PublicKey), zap.String("other_peer", otherPublicKey))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peerIPSets[spec.KubeSpan.PublicKey] = ipSet
|
||||
|
||||
if err = safe.WriterModify(ctx, r, kubespan.NewPeerSpec(kubespan.NamespaceName, spec.KubeSpan.PublicKey), func(res *kubespan.PeerSpec) error {
|
||||
*res.TypedSpec() = kubespan.PeerSpecSpec{
|
||||
Address: spec.KubeSpan.Address,
|
||||
AllowedIPs: ipSet.Prefixes(),
|
||||
Endpoints: slices.Clone(spec.KubeSpan.Endpoints),
|
||||
Label: spec.Nodename,
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
touchedIDs[spec.KubeSpan.PublicKey] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// list keys for cleanup
|
||||
list, err := safe.ReaderListAll[*kubespan.PeerSpec](ctx, r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing resources: %w", err)
|
||||
}
|
||||
|
||||
for it := safe.IteratorFromList(list); it.Next(); {
|
||||
res := it.Value()
|
||||
|
||||
if res.Metadata().Owner() != ctrl.Name() {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := touchedIDs[res.Metadata().ID()]; !ok {
|
||||
if err = r.Destroy(ctx, res.Metadata()); err != nil {
|
||||
return fmt.Errorf("error cleaning up specs: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -90,7 +90,7 @@ func (ctrl *DeviceConfigController) Run(ctx context.Context, r controller.Runtim
|
||||
|
||||
var cfgProvider talosconfig.Config
|
||||
|
||||
cfg, err := safe.ReaderGet[*config.MachineConfig](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
|
||||
cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID)
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting config: %w", err)
|
||||
|
||||
@ -89,6 +89,7 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
|
||||
&cluster.ConfigController{},
|
||||
&cluster.DiscoveryServiceController{},
|
||||
&cluster.EndpointController{},
|
||||
&k8s.APIServerEndpointsController{},
|
||||
&cluster.InfoController{},
|
||||
&cluster.KubernetesPullController{},
|
||||
&cluster.KubernetesPushController{},
|
||||
|
||||
@ -97,6 +97,7 @@ func NewState() (*State, error) {
|
||||
&v1alpha1.Service{},
|
||||
&cluster.Affiliate{},
|
||||
&cluster.Config{},
|
||||
&k8s.APIServerEndpoints{},
|
||||
&cluster.Identity{},
|
||||
&cluster.Info{},
|
||||
&cluster.Member{},
|
||||
|
||||
@ -13,7 +13,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
@ -476,7 +475,7 @@ func (suite *ApplyConfigSuite) TestApplyTry() {
|
||||
nodeCtx := client.WithNode(suite.ctx, node)
|
||||
|
||||
getMachineConfig := func(ctx context.Context) (*mc.MachineConfig, error) {
|
||||
cfg, err := safe.StateGet[*mc.MachineConfig](ctx, suite.Client.COSI, resource.NewMetadata(mc.NamespaceName, mc.MachineConfigType, mc.V1Alpha1ID, resource.VersionUndefined))
|
||||
cfg, err := safe.StateGetByID[*mc.MachineConfig](ctx, suite.Client.COSI, mc.V1Alpha1ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -307,11 +307,7 @@ func (suite *DiscoverySuite) getAffiliates(nodeCtx context.Context, namespace re
|
||||
items, err := safe.StateList[*cluster.Affiliate](nodeCtx, suite.Client.COSI, resource.NewMetadata(namespace, cluster.AffiliateType, "", resource.VersionUndefined))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
it := safe.IteratorFromList(items)
|
||||
|
||||
for it.Next() {
|
||||
result = append(result, it.Value())
|
||||
}
|
||||
items.ForEach(func(item *cluster.Affiliate) { result = append(result, item) })
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/api/machine"
|
||||
@ -29,7 +28,7 @@ func patchNodeConfig(ctx context.Context, cluster UpgradeProvider, node string,
|
||||
|
||||
ctx = client.WithNode(ctx, node)
|
||||
|
||||
mc, err := safe.StateGet[*config.MachineConfig](ctx, c.COSI, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
|
||||
mc, err := safe.StateGetByID[*config.MachineConfig](ctx, c.COSI, config.V1Alpha1ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error fetching config resource: %w", err)
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ type AffiliateSpec struct {
|
||||
OperatingSystem string `protobuf:"bytes,5,opt,name=operating_system,json=operatingSystem,proto3" json:"operating_system,omitempty"`
|
||||
MachineType enums.MachineType `protobuf:"varint,6,opt,name=machine_type,json=machineType,proto3,enum=talos.resource.definitions.enums.MachineType" json:"machine_type,omitempty"`
|
||||
KubeSpan *KubeSpanAffiliateSpec `protobuf:"bytes,7,opt,name=kube_span,json=kubeSpan,proto3" json:"kube_span,omitempty"`
|
||||
ControlPlane *ControlPlane `protobuf:"bytes,8,opt,name=control_plane,json=controlPlane,proto3" json:"control_plane,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AffiliateSpec) Reset() {
|
||||
@ -120,6 +121,13 @@ func (x *AffiliateSpec) GetKubeSpan() *KubeSpanAffiliateSpec {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *AffiliateSpec) GetControlPlane() *ControlPlane {
|
||||
if x != nil {
|
||||
return x.ControlPlane
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigSpec describes KubeSpan configuration.
|
||||
type ConfigSpec struct {
|
||||
state protoimpl.MessageState
|
||||
@ -216,6 +224,54 @@ func (x *ConfigSpec) GetServiceClusterId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ControlPlane describes ControlPlane data if any.
|
||||
type ControlPlane struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
ApiServerPort int64 `protobuf:"varint,1,opt,name=api_server_port,json=apiServerPort,proto3" json:"api_server_port,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ControlPlane) Reset() {
|
||||
*x = ControlPlane{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ControlPlane) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ControlPlane) ProtoMessage() {}
|
||||
|
||||
func (x *ControlPlane) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[2]
|
||||
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 ControlPlane.ProtoReflect.Descriptor instead.
|
||||
func (*ControlPlane) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *ControlPlane) GetApiServerPort() int64 {
|
||||
if x != nil {
|
||||
return x.ApiServerPort
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IdentitySpec describes status of rendered secrets.
|
||||
//
|
||||
// Note: IdentitySpec is persisted on disk in the STATE partition,
|
||||
@ -231,7 +287,7 @@ type IdentitySpec struct {
|
||||
func (x *IdentitySpec) Reset() {
|
||||
*x = IdentitySpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[2]
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -244,7 +300,7 @@ func (x *IdentitySpec) String() string {
|
||||
func (*IdentitySpec) ProtoMessage() {}
|
||||
|
||||
func (x *IdentitySpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[2]
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -257,7 +313,7 @@ func (x *IdentitySpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use IdentitySpec.ProtoReflect.Descriptor instead.
|
||||
func (*IdentitySpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{2}
|
||||
return file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *IdentitySpec) GetNodeId() string {
|
||||
@ -280,7 +336,7 @@ type InfoSpec struct {
|
||||
func (x *InfoSpec) Reset() {
|
||||
*x = InfoSpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[3]
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -293,7 +349,7 @@ func (x *InfoSpec) String() string {
|
||||
func (*InfoSpec) ProtoMessage() {}
|
||||
|
||||
func (x *InfoSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[3]
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -306,7 +362,7 @@ func (x *InfoSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use InfoSpec.ProtoReflect.Descriptor instead.
|
||||
func (*InfoSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{3}
|
||||
return file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *InfoSpec) GetClusterId() string {
|
||||
@ -338,7 +394,7 @@ type KubeSpanAffiliateSpec struct {
|
||||
func (x *KubeSpanAffiliateSpec) Reset() {
|
||||
*x = KubeSpanAffiliateSpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[4]
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -351,7 +407,7 @@ func (x *KubeSpanAffiliateSpec) String() string {
|
||||
func (*KubeSpanAffiliateSpec) ProtoMessage() {}
|
||||
|
||||
func (x *KubeSpanAffiliateSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[4]
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -364,7 +420,7 @@ func (x *KubeSpanAffiliateSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use KubeSpanAffiliateSpec.ProtoReflect.Descriptor instead.
|
||||
func (*KubeSpanAffiliateSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{4}
|
||||
return file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *KubeSpanAffiliateSpec) GetPublicKey() string {
|
||||
@ -406,12 +462,13 @@ type MemberSpec struct {
|
||||
Hostname string `protobuf:"bytes,3,opt,name=hostname,proto3" json:"hostname,omitempty"`
|
||||
MachineType enums.MachineType `protobuf:"varint,4,opt,name=machine_type,json=machineType,proto3,enum=talos.resource.definitions.enums.MachineType" json:"machine_type,omitempty"`
|
||||
OperatingSystem string `protobuf:"bytes,5,opt,name=operating_system,json=operatingSystem,proto3" json:"operating_system,omitempty"`
|
||||
ControlPlane *ControlPlane `protobuf:"bytes,6,opt,name=control_plane,json=controlPlane,proto3" json:"control_plane,omitempty"`
|
||||
}
|
||||
|
||||
func (x *MemberSpec) Reset() {
|
||||
*x = MemberSpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[5]
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -424,7 +481,7 @@ func (x *MemberSpec) String() string {
|
||||
func (*MemberSpec) ProtoMessage() {}
|
||||
|
||||
func (x *MemberSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[5]
|
||||
mi := &file_resource_definitions_cluster_cluster_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -437,7 +494,7 @@ func (x *MemberSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use MemberSpec.ProtoReflect.Descriptor instead.
|
||||
func (*MemberSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{5}
|
||||
return file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *MemberSpec) GetNodeId() string {
|
||||
@ -475,6 +532,13 @@ func (x *MemberSpec) GetOperatingSystem() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MemberSpec) GetControlPlane() *ControlPlane {
|
||||
if x != nil {
|
||||
return x.ControlPlane
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_resource_definitions_cluster_cluster_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_resource_definitions_cluster_cluster_proto_rawDesc = []byte{
|
||||
@ -486,7 +550,7 @@ var file_resource_definitions_cluster_cluster_proto_rawDesc = []byte{
|
||||
0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x26, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f,
|
||||
0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d,
|
||||
0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe2, 0x02,
|
||||
0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb9, 0x03,
|
||||
0x0a, 0x0d, 0x41, 0x66, 0x66, 0x69, 0x6c, 0x69, 0x61, 0x74, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12,
|
||||
0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72,
|
||||
@ -509,72 +573,86 @@ var file_resource_definitions_cluster_cluster_proto_rawDesc = []byte{
|
||||
0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74,
|
||||
0x65, 0x72, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x41, 0x66, 0x66, 0x69, 0x6c,
|
||||
0x69, 0x61, 0x74, 0x65, 0x53, 0x70, 0x65, 0x63, 0x52, 0x08, 0x6b, 0x75, 0x62, 0x65, 0x53, 0x70,
|
||||
0x61, 0x6e, 0x22, 0xfe, 0x02, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65,
|
||||
0x63, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x65,
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x69,
|
||||
0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x3e,
|
||||
0x0a, 0x1b, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x5f, 0x6b, 0x75, 0x62, 0x65, 0x72,
|
||||
0x6e, 0x65, 0x74, 0x65, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x19, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x4b, 0x75, 0x62,
|
||||
0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x38,
|
||||
0x0a, 0x18, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x16, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65,
|
||||
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45,
|
||||
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12,
|
||||
0x34, 0x0a, 0x16, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79,
|
||||
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x14, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x10, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65,
|
||||
0x72, 0x49, 0x64, 0x22, 0x27, 0x0a, 0x0c, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53,
|
||||
0x61, 0x6e, 0x12, 0x55, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c,
|
||||
0x61, 0x6e, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 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, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x43,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x52, 0x0c, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x22, 0xfe, 0x02, 0x0a, 0x0a, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x69, 0x73, 0x63,
|
||||
0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x45, 0x6e,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x3e, 0x0a, 0x1b, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
|
||||
0x79, 0x5f, 0x6b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x5f, 0x65, 0x6e, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x72, 0x65, 0x67, 0x69,
|
||||
0x73, 0x74, 0x72, 0x79, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x45, 0x6e,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
|
||||
0x79, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
||||
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
|
||||
0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,
|
||||
0x29, 0x0a, 0x10, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x19, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x69,
|
||||
0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x73,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x49, 0x6e,
|
||||
0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79,
|
||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45,
|
||||
0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x12,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0x36, 0x0a, 0x0c, 0x43, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x70,
|
||||
0x69, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x03, 0x52, 0x0d, 0x61, 0x70, 0x69, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x6f,
|
||||
0x72, 0x74, 0x22, 0x27, 0x0a, 0x0c, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x70,
|
||||
0x65, 0x63, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x22, 0x4c, 0x0a, 0x08, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74,
|
||||
0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75,
|
||||
0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
|
||||
0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c,
|
||||
0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xd8, 0x01, 0x0a, 0x15, 0x4b, 0x75,
|
||||
0x62, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x41, 0x66, 0x66, 0x69, 0x6c, 0x69, 0x61, 0x74, 0x65, 0x53,
|
||||
0x70, 0x65, 0x63, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
|
||||
0x65, 0x79, 0x12, 0x27, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74,
|
||||
0x49, 0x50, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x46, 0x0a, 0x14, 0x61,
|
||||
0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
|
||||
0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x50, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52, 0x13,
|
||||
0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
|
||||
0x73, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73,
|
||||
0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
|
||||
0x4e, 0x65, 0x74, 0x49, 0x50, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x73, 0x22, 0xc2, 0x02, 0x0a, 0x0a, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x53,
|
||||
0x70, 0x65, 0x63, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x22, 0x4c, 0x0a, 0x08,
|
||||
0x49, 0x6e, 0x66, 0x6f, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73,
|
||||
0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c,
|
||||
0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74,
|
||||
0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63,
|
||||
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xd8, 0x01, 0x0a, 0x15, 0x4b,
|
||||
0x75, 0x62, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x41, 0x66, 0x66, 0x69, 0x6c, 0x69, 0x61, 0x74, 0x65,
|
||||
0x53, 0x70, 0x65, 0x63, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b,
|
||||
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
|
||||
0x4b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65,
|
||||
0x74, 0x49, 0x50, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x46, 0x0a, 0x14,
|
||||
0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65,
|
||||
0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x50, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x52,
|
||||
0x13, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65,
|
||||
0x73, 0x73, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x4e, 0x65, 0x74, 0x49, 0x50, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70,
|
||||
0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0xeb, 0x01, 0x0a, 0x0a, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72,
|
||||
0x53, 0x70, 0x65, 0x63, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x2b, 0x0a,
|
||||
0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x50, 0x52,
|
||||
0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f,
|
||||
0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f,
|
||||
0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0c, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
||||
0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 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, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e,
|
||||
0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x6d, 0x61, 0x63,
|
||||
0x68, 0x69, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72,
|
||||
0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x05, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x79, 0x73,
|
||||
0x74, 0x65, 0x6d, 0x42, 0x4c, 0x5a, 0x4a, 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, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
|
||||
0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x09,
|
||||
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x50, 0x52, 0x09,
|
||||
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73,
|
||||
0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73,
|
||||
0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0c, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
|
||||
0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 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, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x4d,
|
||||
0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x6d, 0x61, 0x63, 0x68,
|
||||
0x69, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x79, 0x73, 0x74,
|
||||
0x65, 0x6d, 0x12, 0x55, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x70, 0x6c,
|
||||
0x61, 0x6e, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 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, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x43,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x52, 0x0c, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x42, 0x4c, 0x5a, 0x4a, 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,
|
||||
0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -589,33 +667,36 @@ func file_resource_definitions_cluster_cluster_proto_rawDescGZIP() []byte {
|
||||
return file_resource_definitions_cluster_cluster_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_resource_definitions_cluster_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_resource_definitions_cluster_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||
var file_resource_definitions_cluster_cluster_proto_goTypes = []interface{}{
|
||||
(*AffiliateSpec)(nil), // 0: talos.resource.definitions.cluster.AffiliateSpec
|
||||
(*ConfigSpec)(nil), // 1: talos.resource.definitions.cluster.ConfigSpec
|
||||
(*IdentitySpec)(nil), // 2: talos.resource.definitions.cluster.IdentitySpec
|
||||
(*InfoSpec)(nil), // 3: talos.resource.definitions.cluster.InfoSpec
|
||||
(*KubeSpanAffiliateSpec)(nil), // 4: talos.resource.definitions.cluster.KubeSpanAffiliateSpec
|
||||
(*MemberSpec)(nil), // 5: talos.resource.definitions.cluster.MemberSpec
|
||||
(*common.NetIP)(nil), // 6: common.NetIP
|
||||
(enums.MachineType)(0), // 7: talos.resource.definitions.enums.MachineType
|
||||
(*common.NetIPPrefix)(nil), // 8: common.NetIPPrefix
|
||||
(*common.NetIPPort)(nil), // 9: common.NetIPPort
|
||||
(*ControlPlane)(nil), // 2: talos.resource.definitions.cluster.ControlPlane
|
||||
(*IdentitySpec)(nil), // 3: talos.resource.definitions.cluster.IdentitySpec
|
||||
(*InfoSpec)(nil), // 4: talos.resource.definitions.cluster.InfoSpec
|
||||
(*KubeSpanAffiliateSpec)(nil), // 5: talos.resource.definitions.cluster.KubeSpanAffiliateSpec
|
||||
(*MemberSpec)(nil), // 6: talos.resource.definitions.cluster.MemberSpec
|
||||
(*common.NetIP)(nil), // 7: common.NetIP
|
||||
(enums.MachineType)(0), // 8: talos.resource.definitions.enums.MachineType
|
||||
(*common.NetIPPrefix)(nil), // 9: common.NetIPPrefix
|
||||
(*common.NetIPPort)(nil), // 10: common.NetIPPort
|
||||
}
|
||||
var file_resource_definitions_cluster_cluster_proto_depIdxs = []int32{
|
||||
6, // 0: talos.resource.definitions.cluster.AffiliateSpec.addresses:type_name -> common.NetIP
|
||||
7, // 1: talos.resource.definitions.cluster.AffiliateSpec.machine_type:type_name -> talos.resource.definitions.enums.MachineType
|
||||
4, // 2: talos.resource.definitions.cluster.AffiliateSpec.kube_span:type_name -> talos.resource.definitions.cluster.KubeSpanAffiliateSpec
|
||||
6, // 3: talos.resource.definitions.cluster.KubeSpanAffiliateSpec.address:type_name -> common.NetIP
|
||||
8, // 4: talos.resource.definitions.cluster.KubeSpanAffiliateSpec.additional_addresses:type_name -> common.NetIPPrefix
|
||||
9, // 5: talos.resource.definitions.cluster.KubeSpanAffiliateSpec.endpoints:type_name -> common.NetIPPort
|
||||
6, // 6: talos.resource.definitions.cluster.MemberSpec.addresses:type_name -> common.NetIP
|
||||
7, // 7: talos.resource.definitions.cluster.MemberSpec.machine_type:type_name -> talos.resource.definitions.enums.MachineType
|
||||
8, // [8:8] is the sub-list for method output_type
|
||||
8, // [8:8] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
7, // 0: talos.resource.definitions.cluster.AffiliateSpec.addresses:type_name -> common.NetIP
|
||||
8, // 1: talos.resource.definitions.cluster.AffiliateSpec.machine_type:type_name -> talos.resource.definitions.enums.MachineType
|
||||
5, // 2: talos.resource.definitions.cluster.AffiliateSpec.kube_span:type_name -> talos.resource.definitions.cluster.KubeSpanAffiliateSpec
|
||||
2, // 3: talos.resource.definitions.cluster.AffiliateSpec.control_plane:type_name -> talos.resource.definitions.cluster.ControlPlane
|
||||
7, // 4: talos.resource.definitions.cluster.KubeSpanAffiliateSpec.address:type_name -> common.NetIP
|
||||
9, // 5: talos.resource.definitions.cluster.KubeSpanAffiliateSpec.additional_addresses:type_name -> common.NetIPPrefix
|
||||
10, // 6: talos.resource.definitions.cluster.KubeSpanAffiliateSpec.endpoints:type_name -> common.NetIPPort
|
||||
7, // 7: talos.resource.definitions.cluster.MemberSpec.addresses:type_name -> common.NetIP
|
||||
8, // 8: talos.resource.definitions.cluster.MemberSpec.machine_type:type_name -> talos.resource.definitions.enums.MachineType
|
||||
2, // 9: talos.resource.definitions.cluster.MemberSpec.control_plane:type_name -> talos.resource.definitions.cluster.ControlPlane
|
||||
10, // [10:10] is the sub-list for method output_type
|
||||
10, // [10:10] is the sub-list for method input_type
|
||||
10, // [10:10] is the sub-list for extension type_name
|
||||
10, // [10:10] is the sub-list for extension extendee
|
||||
0, // [0:10] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_resource_definitions_cluster_cluster_proto_init() }
|
||||
@ -649,7 +730,7 @@ func file_resource_definitions_cluster_cluster_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_cluster_cluster_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*IdentitySpec); i {
|
||||
switch v := v.(*ControlPlane); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -661,7 +742,7 @@ func file_resource_definitions_cluster_cluster_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_cluster_cluster_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*InfoSpec); i {
|
||||
switch v := v.(*IdentitySpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -673,7 +754,7 @@ func file_resource_definitions_cluster_cluster_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_cluster_cluster_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*KubeSpanAffiliateSpec); i {
|
||||
switch v := v.(*InfoSpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -685,6 +766,18 @@ func file_resource_definitions_cluster_cluster_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_cluster_cluster_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*KubeSpanAffiliateSpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_resource_definitions_cluster_cluster_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*MemberSpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@ -703,7 +796,7 @@ func file_resource_definitions_cluster_cluster_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_resource_definitions_cluster_cluster_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 6,
|
||||
NumMessages: 7,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@ -53,6 +53,16 @@ func (m *AffiliateSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if m.ControlPlane != nil {
|
||||
size, err := m.ControlPlane.MarshalToSizedBufferVT(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarint(dAtA, i, uint64(size))
|
||||
i--
|
||||
dAtA[i] = 0x42
|
||||
}
|
||||
if m.KubeSpan != nil {
|
||||
size, err := m.KubeSpan.MarshalToSizedBufferVT(dAtA[:i])
|
||||
if err != nil {
|
||||
@ -217,6 +227,44 @@ func (m *ConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *ControlPlane) 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 *ControlPlane) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *ControlPlane) 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.ApiServerPort != 0 {
|
||||
i = encodeVarint(dAtA, i, uint64(m.ApiServerPort))
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *IdentitySpec) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
@ -444,6 +492,16 @@ func (m *MemberSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if m.ControlPlane != nil {
|
||||
size, err := m.ControlPlane.MarshalToSizedBufferVT(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarint(dAtA, i, uint64(size))
|
||||
i--
|
||||
dAtA[i] = 0x32
|
||||
}
|
||||
if len(m.OperatingSystem) > 0 {
|
||||
i -= len(m.OperatingSystem)
|
||||
copy(dAtA[i:], m.OperatingSystem)
|
||||
@ -549,6 +607,10 @@ func (m *AffiliateSpec) SizeVT() (n int) {
|
||||
l = m.KubeSpan.SizeVT()
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
if m.ControlPlane != nil {
|
||||
l = m.ControlPlane.SizeVT()
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
@ -587,6 +649,19 @@ func (m *ConfigSpec) SizeVT() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *ControlPlane) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.ApiServerPort != 0 {
|
||||
n += 1 + sov(uint64(m.ApiServerPort))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *IdentitySpec) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@ -700,6 +775,10 @@ func (m *MemberSpec) SizeVT() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
if m.ControlPlane != nil {
|
||||
l = m.ControlPlane.SizeVT()
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
@ -964,6 +1043,42 @@ func (m *AffiliateSpec) UnmarshalVT(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 8:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ControlPlane", 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
|
||||
}
|
||||
if m.ControlPlane == nil {
|
||||
m.ControlPlane = &ControlPlane{}
|
||||
}
|
||||
if err := m.ControlPlane.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
@ -1215,6 +1330,76 @@ func (m *ConfigSpec) UnmarshalVT(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *ControlPlane) 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 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: ControlPlane: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: ControlPlane: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ApiServerPort", wireType)
|
||||
}
|
||||
m.ApiServerPort = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.ApiServerPort |= int64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return 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 *IdentitySpec) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
@ -1810,6 +1995,42 @@ func (m *MemberSpec) UnmarshalVT(dAtA []byte) error {
|
||||
}
|
||||
m.OperatingSystem = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 6:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ControlPlane", 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
|
||||
}
|
||||
if m.ControlPlane == nil {
|
||||
m.ControlPlane = &ControlPlane{}
|
||||
}
|
||||
if err := m.ControlPlane.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -168,6 +168,96 @@ func (m *APIServerConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *APIServerEndpoint) 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 *APIServerEndpoint) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *APIServerEndpoint) 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.Port != 0 {
|
||||
i = encodeVarint(dAtA, i, uint64(m.Port))
|
||||
i--
|
||||
dAtA[i] = 0x10
|
||||
}
|
||||
if len(m.Host) > 0 {
|
||||
i -= len(m.Host)
|
||||
copy(dAtA[i:], m.Host)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Host)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *APIServerEndpointsSpec) 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 *APIServerEndpointsSpec) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *APIServerEndpointsSpec) 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 len(m.Endpoints) > 0 {
|
||||
for iNdEx := len(m.Endpoints) - 1; iNdEx >= 0; iNdEx-- {
|
||||
size, err := m.Endpoints[iNdEx].MarshalToSizedBufferVT(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarint(dAtA, i, uint64(size))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *AdmissionControlConfigSpec) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
@ -1909,6 +1999,39 @@ func (m *APIServerConfigSpec) SizeVT() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *APIServerEndpoint) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Host)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
if m.Port != 0 {
|
||||
n += 1 + sov(uint64(m.Port))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *APIServerEndpointsSpec) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Endpoints) > 0 {
|
||||
for _, e := range m.Endpoints {
|
||||
l = e.SizeVT()
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *AdmissionControlConfigSpec) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@ -3144,6 +3267,193 @@ func (m *APIServerConfigSpec) UnmarshalVT(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *APIServerEndpoint) 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 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: APIServerEndpoint: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: APIServerEndpoint: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
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 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 ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Host = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Port", wireType)
|
||||
}
|
||||
m.Port = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Port |= uint32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return 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 *APIServerEndpointsSpec) 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 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: APIServerEndpointsSpec: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: APIServerEndpointsSpec: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Endpoints", 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.Endpoints = append(m.Endpoints, &APIServerEndpoint{})
|
||||
if err := m.Endpoints[len(m.Endpoints)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return 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 *AdmissionControlConfigSpec) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
|
||||
@ -8,7 +8,7 @@ replace gopkg.in/yaml.v3 => github.com/unix4ever/yaml v0.0.0-20220527175918-f17b
|
||||
|
||||
require (
|
||||
github.com/containerd/go-cni v1.1.9
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.3
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.4
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
@ -27,7 +27,7 @@ require (
|
||||
github.com/siderolabs/go-pointer v1.0.0
|
||||
github.com/siderolabs/net v0.4.0
|
||||
github.com/siderolabs/protoenc v0.2.0
|
||||
github.com/stretchr/testify v1.8.3
|
||||
github.com/stretchr/testify v1.8.4
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19
|
||||
google.golang.org/grpc v1.55.0
|
||||
google.golang.org/protobuf v1.30.0
|
||||
|
||||
@ -21,8 +21,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.1-alpha.3 h1:8IDeG7b64OCTMHlngEKWTHTYKCfJ1oMVDxP3y0yuKbU=
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.3/go.mod h1:g+0MZ3+2MIUkUL7JYTqgYeo5f4j7dAuGem6apjBJ1XU=
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.4 h1:TXrn1ka+pw2YeywKZjA9b4mNoz4a9HBX9ovR4YtkDGc=
|
||||
github.com/cosi-project/runtime v0.3.1-alpha.4/go.mod h1:GubXzK7vQFe4VyrWL/eXaMU4T1pXBx9KoDj0GJz6miw=
|
||||
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=
|
||||
@ -131,8 +131,8 @@ github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/unix4ever/yaml v0.0.0-20220527175918-f17b0f05cf2c h1:Vn6nVVu9MdOYvXPkJP83iX5jVIfvxFC9v9xIKb+DlaQ=
|
||||
github.com/unix4ever/yaml v0.0.0-20220527175918-f17b0f05cf2c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
||||
@ -82,6 +82,14 @@ type AffiliateSpec struct {
|
||||
OperatingSystem string `yaml:"operatingSystem" protobuf:"5"`
|
||||
MachineType machine.Type `yaml:"machineType" protobuf:"6"`
|
||||
KubeSpan KubeSpanAffiliateSpec `yaml:"kubespan,omitempty" protobuf:"7"`
|
||||
ControlPlane *ControlPlane `yaml:"controlPlane,omitempty" protobuf:"8"`
|
||||
}
|
||||
|
||||
// ControlPlane describes ControlPlane data if any.
|
||||
//
|
||||
//gotagsrewrite:gen
|
||||
type ControlPlane struct {
|
||||
APIServerPort int `yaml:"port" protobuf:"1"`
|
||||
}
|
||||
|
||||
// Merge two AffiliateSpecs.
|
||||
@ -104,6 +112,10 @@ func (spec *AffiliateSpec) Merge(other *AffiliateSpec) {
|
||||
}
|
||||
}
|
||||
|
||||
if other.ControlPlane != nil {
|
||||
spec.ControlPlane = other.ControlPlane
|
||||
}
|
||||
|
||||
if other.Hostname != "" {
|
||||
spec.Hostname = other.Hostname
|
||||
}
|
||||
|
||||
@ -8,9 +8,13 @@ import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/siderolabs/protoenc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
cluster2 "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/cluster"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/proto"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
|
||||
)
|
||||
|
||||
@ -25,10 +29,11 @@ func TestAffiliateSpec_Merge(t *testing.T) {
|
||||
{
|
||||
name: "merge kubespan",
|
||||
a: cluster.AffiliateSpec{
|
||||
Hostname: "foo.com",
|
||||
Nodename: "bar",
|
||||
MachineType: machine.TypeControlPlane,
|
||||
Addresses: []netip.Addr{netip.MustParseAddr("10.0.0.2")},
|
||||
Hostname: "foo.com",
|
||||
Nodename: "bar",
|
||||
MachineType: machine.TypeControlPlane,
|
||||
Addresses: []netip.Addr{netip.MustParseAddr("10.0.0.2")},
|
||||
ControlPlane: &cluster.ControlPlane{APIServerPort: 6443},
|
||||
},
|
||||
b: cluster.AffiliateSpec{
|
||||
Hostname: "foo.com",
|
||||
@ -53,6 +58,7 @@ func TestAffiliateSpec_Merge(t *testing.T) {
|
||||
AdditionalAddresses: []netip.Prefix{netip.MustParsePrefix("10.244.3.1/24")},
|
||||
Endpoints: []netip.AddrPort{netip.MustParseAddrPort("10.0.0.2:51820"), netip.MustParseAddrPort("192.168.3.4:51820")},
|
||||
},
|
||||
ControlPlane: &cluster.ControlPlane{APIServerPort: 6443},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -76,6 +82,7 @@ func TestAffiliateSpec_Merge(t *testing.T) {
|
||||
AdditionalAddresses: []netip.Prefix{netip.MustParsePrefix("10.244.3.1/24")},
|
||||
Endpoints: []netip.AddrPort{netip.MustParseAddrPort("10.0.0.2:51820"), netip.MustParseAddrPort("192.168.3.4:51820")},
|
||||
},
|
||||
ControlPlane: &cluster.ControlPlane{APIServerPort: 6443},
|
||||
},
|
||||
expected: cluster.AffiliateSpec{
|
||||
Hostname: "foo.com",
|
||||
@ -88,6 +95,7 @@ func TestAffiliateSpec_Merge(t *testing.T) {
|
||||
AdditionalAddresses: []netip.Prefix{netip.MustParsePrefix("10.244.3.1/24")},
|
||||
Endpoints: []netip.AddrPort{netip.MustParseAddrPort("192.168.3.4:51820"), netip.MustParseAddrPort("10.0.0.2:51820")},
|
||||
},
|
||||
ControlPlane: &cluster.ControlPlane{APIServerPort: 6443},
|
||||
},
|
||||
},
|
||||
} {
|
||||
@ -101,3 +109,38 @@ func TestAffiliateSpec_Merge(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAffiliateSpecMarshal(t *testing.T) {
|
||||
original := &cluster.AffiliateSpec{
|
||||
NodeID: "myNodeID",
|
||||
Hostname: "foo.com",
|
||||
MachineType: machine.TypeControlPlane,
|
||||
ControlPlane: &cluster.ControlPlane{APIServerPort: 6443},
|
||||
}
|
||||
|
||||
wire, err := protoenc.Marshal(original)
|
||||
require.NoError(t, err)
|
||||
|
||||
var unmarshaled cluster2.AffiliateSpec
|
||||
|
||||
err = proto.Unmarshal(wire, &unmarshaled)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.EqualValues(t, original.NodeID, unmarshaled.NodeId)
|
||||
require.EqualValues(t, original.Hostname, unmarshaled.Hostname)
|
||||
require.EqualValues(t, original.MachineType, unmarshaled.MachineType)
|
||||
require.EqualValues(t, original.ControlPlane.APIServerPort, unmarshaled.ControlPlane.ApiServerPort)
|
||||
|
||||
unmarshaled.ControlPlane = nil
|
||||
|
||||
wire, err = proto.Marshal(&unmarshaled)
|
||||
require.NoError(t, err)
|
||||
|
||||
spec := &cluster.AffiliateSpec{}
|
||||
err = protoenc.Unmarshal(wire, spec)
|
||||
require.NoError(t, err)
|
||||
|
||||
original.ControlPlane = nil
|
||||
|
||||
require.Equal(t, original, spec)
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/cluster"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/k8s"
|
||||
)
|
||||
|
||||
func TestRegisterResource(t *testing.T) {
|
||||
@ -27,6 +28,7 @@ func TestRegisterResource(t *testing.T) {
|
||||
for _, resource := range []resource.Resource{
|
||||
&cluster.Affiliate{},
|
||||
&cluster.Config{},
|
||||
&k8s.APIServerEndpoints{},
|
||||
&cluster.Identity{},
|
||||
&cluster.Member{},
|
||||
} {
|
||||
|
||||
@ -25,6 +25,10 @@ func (o AffiliateSpec) DeepCopy() AffiliateSpec {
|
||||
cp.KubeSpan.Endpoints = make([]netip.AddrPort, len(o.KubeSpan.Endpoints))
|
||||
copy(cp.KubeSpan.Endpoints, o.KubeSpan.Endpoints)
|
||||
}
|
||||
if o.ControlPlane != nil {
|
||||
cp.ControlPlane = new(ControlPlane)
|
||||
*cp.ControlPlane = *o.ControlPlane
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
@ -51,6 +55,10 @@ func (o MemberSpec) DeepCopy() MemberSpec {
|
||||
cp.Addresses = make([]netip.Addr, len(o.Addresses))
|
||||
copy(cp.Addresses, o.Addresses)
|
||||
}
|
||||
if o.ControlPlane != nil {
|
||||
cp.ControlPlane = new(ControlPlane)
|
||||
*cp.ControlPlane = *o.ControlPlane
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
|
||||
@ -28,11 +28,12 @@ type Member = typed.Resource[MemberSpec, MemberExtension]
|
||||
//
|
||||
//gotagsrewrite:gen
|
||||
type MemberSpec struct {
|
||||
NodeID string `yaml:"nodeId" protobuf:"1"`
|
||||
Addresses []netip.Addr `yaml:"addresses" protobuf:"2"`
|
||||
Hostname string `yaml:"hostname" protobuf:"3"`
|
||||
MachineType machine.Type `yaml:"machineType" protobuf:"4"`
|
||||
OperatingSystem string `yaml:"operatingSystem" protobuf:"5"`
|
||||
NodeID string `yaml:"nodeId" protobuf:"1"`
|
||||
Addresses []netip.Addr `yaml:"addresses" protobuf:"2"`
|
||||
Hostname string `yaml:"hostname" protobuf:"3"`
|
||||
MachineType machine.Type `yaml:"machineType" protobuf:"4"`
|
||||
OperatingSystem string `yaml:"operatingSystem" protobuf:"5"`
|
||||
ControlPlane *ControlPlane `yaml:"controlPlane,omitempty" protobuf:"6"`
|
||||
}
|
||||
|
||||
// NewMember initializes a Member resource.
|
||||
|
||||
84
pkg/machinery/resources/k8s/apiserver_endpoints.go
Normal file
84
pkg/machinery/resources/k8s/apiserver_endpoints.go
Normal file
@ -0,0 +1,84 @@
|
||||
// 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 k8s
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// APIServerEndpointsType is type of APIServerEndpoints resource.
|
||||
const APIServerEndpointsType = resource.Type("APIServerEndpoints.cluster.talos.dev")
|
||||
|
||||
// APIServerEndpointsID the singleton balancer data resource ID.
|
||||
const APIServerEndpointsID = resource.ID("k8s-cluster")
|
||||
|
||||
// APIServerEndpoints resource holds endpoints data.
|
||||
type APIServerEndpoints = typed.Resource[APIServerEndpointsSpec, APIServerEndpointsExtension]
|
||||
|
||||
// NewEndpoints initializes an APIServerEndpoints resource.
|
||||
func NewEndpoints(namespace resource.Namespace, id resource.ID) *APIServerEndpoints {
|
||||
return typed.NewResource[APIServerEndpointsSpec, APIServerEndpointsExtension](
|
||||
resource.NewMetadata(namespace, APIServerEndpointsType, id, resource.VersionUndefined),
|
||||
APIServerEndpointsSpec{},
|
||||
)
|
||||
}
|
||||
|
||||
// APIServerEndpointsSpec describes APIServerEndpoints configuration.
|
||||
//
|
||||
//gotagsrewrite:gen
|
||||
type APIServerEndpointsSpec struct {
|
||||
Endpoints []APIServerEndpoint `yaml:"endpoints" protobuf:"1"`
|
||||
}
|
||||
|
||||
// APIServerEndpoint holds data for control plane endpoint.
|
||||
//
|
||||
//gotagsrewrite:gen
|
||||
type APIServerEndpoint struct {
|
||||
Host string `yaml:"host" protobuf:"1"`
|
||||
Port uint32 `yaml:"port" protobuf:"2"`
|
||||
}
|
||||
|
||||
// String returns string representation of APIServerEndpoint.
|
||||
func (e APIServerEndpoint) String() string {
|
||||
return fmt.Sprintf("host: %s, port: %d", e.Host, e.Port)
|
||||
}
|
||||
|
||||
// APIServerEndpointsExtension provides auxiliary methods for APIServerEndpoints.
|
||||
type APIServerEndpointsExtension struct{}
|
||||
|
||||
// ResourceDefinition implements [typed.Extension] interface.
|
||||
func (APIServerEndpointsExtension) ResourceDefinition() meta.ResourceDefinitionSpec {
|
||||
return meta.ResourceDefinitionSpec{
|
||||
Type: APIServerEndpointsType,
|
||||
Aliases: []resource.Type{},
|
||||
DefaultNamespace: NamespaceName,
|
||||
PrintColumns: []meta.PrintColumn{
|
||||
{
|
||||
Name: "Hosts",
|
||||
JSONPath: ".endpoints[*].host",
|
||||
},
|
||||
{
|
||||
Name: "Ports",
|
||||
JSONPath: ".endpoints[*].port",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterDefaultTypes()
|
||||
|
||||
err := protobuf.RegisterDynamic[APIServerEndpointsSpec](APIServerEndpointsType, &APIServerEndpoints{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@ -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 AdmissionControlConfigSpec -type APIServerConfigSpec -type AuditPolicyConfigSpec -type BootstrapManifestsConfigSpec -type ConfigStatusSpec -type ControllerManagerConfigSpec -type EndpointSpec -type ExtraManifestsConfigSpec -type KubeletLifecycleSpec -type KubeletSpecSpec -type ManifestSpec -type ManifestStatusSpec -type NodeLabelSpecSpec -type KubeletConfigSpec -type NodeIPSpec -type NodeIPConfigSpec -type NodenameSpec -type SchedulerConfigSpec -type SecretsStatusSpec -type StaticPodSpec -type StaticPodStatusSpec -type StaticPodServerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
|
||||
// Code generated by "deep-copy -type AdmissionControlConfigSpec -type APIServerEndpointsSpec -type APIServerConfigSpec -type AuditPolicyConfigSpec -type BootstrapManifestsConfigSpec -type ConfigStatusSpec -type ControllerManagerConfigSpec -type EndpointSpec -type ExtraManifestsConfigSpec -type KubeletLifecycleSpec -type KubeletSpecSpec -type ManifestSpec -type ManifestStatusSpec -type NodeLabelSpecSpec -type KubeletConfigSpec -type NodeIPSpec -type NodeIPConfigSpec -type NodenameSpec -type SchedulerConfigSpec -type SecretsStatusSpec -type StaticPodSpec -type StaticPodStatusSpec -type StaticPodServerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
|
||||
|
||||
package k8s
|
||||
|
||||
@ -30,6 +30,16 @@ func (o AdmissionControlConfigSpec) DeepCopy() AdmissionControlConfigSpec {
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of APIServerEndpointsSpec.
|
||||
func (o APIServerEndpointsSpec) DeepCopy() APIServerEndpointsSpec {
|
||||
var cp APIServerEndpointsSpec = o
|
||||
if o.Endpoints != nil {
|
||||
cp.Endpoints = make([]APIServerEndpoint, len(o.Endpoints))
|
||||
copy(cp.Endpoints, o.Endpoints)
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of APIServerConfigSpec.
|
||||
func (o APIServerConfigSpec) DeepCopy() APIServerConfigSpec {
|
||||
var cp APIServerConfigSpec = o
|
||||
@ -310,7 +320,7 @@ func (o SecretsStatusSpec) DeepCopy() SecretsStatusSpec {
|
||||
func (o StaticPodSpec) DeepCopy() StaticPodSpec {
|
||||
var cp StaticPodSpec = o
|
||||
if o.Pod != nil {
|
||||
cp.Pod = make(map[string]interface{}, len(o.Pod))
|
||||
cp.Pod = make(map[string]any, len(o.Pod))
|
||||
for k2, v2 := range o.Pod {
|
||||
cp.Pod[k2] = v2
|
||||
}
|
||||
@ -322,7 +332,7 @@ func (o StaticPodSpec) DeepCopy() StaticPodSpec {
|
||||
func (o StaticPodStatusSpec) DeepCopy() StaticPodStatusSpec {
|
||||
var cp StaticPodStatusSpec = o
|
||||
if o.PodStatus != nil {
|
||||
cp.PodStatus = make(map[string]interface{}, len(o.PodStatus))
|
||||
cp.PodStatus = make(map[string]any, len(o.PodStatus))
|
||||
for k2, v2 := range o.PodStatus {
|
||||
cp.PodStatus[k2] = v2
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ package k8s
|
||||
import "github.com/cosi-project/runtime/pkg/resource"
|
||||
|
||||
//nolint:lll
|
||||
//go:generate deep-copy -type AdmissionControlConfigSpec -type APIServerConfigSpec -type AuditPolicyConfigSpec -type BootstrapManifestsConfigSpec -type ConfigStatusSpec -type ControllerManagerConfigSpec -type EndpointSpec -type ExtraManifestsConfigSpec -type KubeletLifecycleSpec -type KubeletSpecSpec -type ManifestSpec -type ManifestStatusSpec -type NodeLabelSpecSpec -type KubeletConfigSpec -type NodeIPSpec -type NodeIPConfigSpec -type NodenameSpec -type SchedulerConfigSpec -type SecretsStatusSpec -type StaticPodSpec -type StaticPodStatusSpec -type StaticPodServerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
|
||||
//go:generate deep-copy -type AdmissionControlConfigSpec -type APIServerEndpointsSpec -type APIServerConfigSpec -type AuditPolicyConfigSpec -type BootstrapManifestsConfigSpec -type ConfigStatusSpec -type ControllerManagerConfigSpec -type EndpointSpec -type ExtraManifestsConfigSpec -type KubeletLifecycleSpec -type KubeletSpecSpec -type ManifestSpec -type ManifestStatusSpec -type NodeLabelSpecSpec -type KubeletConfigSpec -type NodeIPSpec -type NodeIPConfigSpec -type NodenameSpec -type SchedulerConfigSpec -type SecretsStatusSpec -type StaticPodSpec -type StaticPodStatusSpec -type StaticPodServerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
|
||||
|
||||
// NamespaceName contains resources supporting Kubernetes components on all node types.
|
||||
const NamespaceName resource.Namespace = "k8s"
|
||||
|
||||
@ -23,7 +23,7 @@ type StaticPod = typed.Resource[StaticPodSpec, StaticPodExtension]
|
||||
//
|
||||
//gotagsrewrite:gen
|
||||
type StaticPodSpec struct {
|
||||
Pod map[string]interface{} `protobuf:"1"`
|
||||
Pod map[string]any `protobuf:"1"`
|
||||
}
|
||||
|
||||
// MarshalYAML implements yaml.Marshaler.
|
||||
|
||||
@ -23,7 +23,7 @@ type StaticPodStatus = typed.Resource[StaticPodStatusSpec, StaticPodStatusExtens
|
||||
//
|
||||
//gotagsrewrite:gen
|
||||
type StaticPodStatusSpec struct {
|
||||
PodStatus map[string]interface{} `protobuf:"1"`
|
||||
PodStatus map[string]any `protobuf:"1"`
|
||||
}
|
||||
|
||||
// MarshalYAML implements yaml.Marshaler.
|
||||
|
||||
@ -27,6 +27,7 @@ description: Talos gRPC API reference.
|
||||
- [resource/definitions/cluster/cluster.proto](#resource/definitions/cluster/cluster.proto)
|
||||
- [AffiliateSpec](#talos.resource.definitions.cluster.AffiliateSpec)
|
||||
- [ConfigSpec](#talos.resource.definitions.cluster.ConfigSpec)
|
||||
- [ControlPlane](#talos.resource.definitions.cluster.ControlPlane)
|
||||
- [IdentitySpec](#talos.resource.definitions.cluster.IdentitySpec)
|
||||
- [InfoSpec](#talos.resource.definitions.cluster.InfoSpec)
|
||||
- [KubeSpanAffiliateSpec](#talos.resource.definitions.cluster.KubeSpanAffiliateSpec)
|
||||
@ -89,6 +90,8 @@ description: Talos gRPC API reference.
|
||||
- [APIServerConfigSpec](#talos.resource.definitions.k8s.APIServerConfigSpec)
|
||||
- [APIServerConfigSpec.EnvironmentVariablesEntry](#talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntry)
|
||||
- [APIServerConfigSpec.ExtraArgsEntry](#talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry)
|
||||
- [APIServerEndpoint](#talos.resource.definitions.k8s.APIServerEndpoint)
|
||||
- [APIServerEndpointsSpec](#talos.resource.definitions.k8s.APIServerEndpointsSpec)
|
||||
- [AdmissionControlConfigSpec](#talos.resource.definitions.k8s.AdmissionControlConfigSpec)
|
||||
- [AdmissionPluginSpec](#talos.resource.definitions.k8s.AdmissionPluginSpec)
|
||||
- [AuditPolicyConfigSpec](#talos.resource.definitions.k8s.AuditPolicyConfigSpec)
|
||||
@ -686,6 +689,7 @@ AffiliateSpec describes Affiliate state.
|
||||
| operating_system | [string](#string) | | |
|
||||
| machine_type | [talos.resource.definitions.enums.MachineType](#talos.resource.definitions.enums.MachineType) | | |
|
||||
| kube_span | [KubeSpanAffiliateSpec](#talos.resource.definitions.cluster.KubeSpanAffiliateSpec) | | |
|
||||
| control_plane | [ControlPlane](#talos.resource.definitions.cluster.ControlPlane) | | |
|
||||
|
||||
|
||||
|
||||
@ -713,6 +717,21 @@ ConfigSpec describes KubeSpan configuration.
|
||||
|
||||
|
||||
|
||||
<a name="talos.resource.definitions.cluster.ControlPlane"></a>
|
||||
|
||||
### ControlPlane
|
||||
ControlPlane describes ControlPlane data if any.
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| api_server_port | [int64](#int64) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="talos.resource.definitions.cluster.IdentitySpec"></a>
|
||||
|
||||
### IdentitySpec
|
||||
@ -778,6 +797,7 @@ MemberSpec describes Member state.
|
||||
| hostname | [string](#string) | | |
|
||||
| machine_type | [talos.resource.definitions.enums.MachineType](#talos.resource.definitions.enums.MachineType) | | |
|
||||
| operating_system | [string](#string) | | |
|
||||
| control_plane | [ControlPlane](#talos.resource.definitions.cluster.ControlPlane) | | |
|
||||
|
||||
|
||||
|
||||
@ -1706,6 +1726,37 @@ APIServerConfigSpec is configuration for kube-apiserver.
|
||||
|
||||
|
||||
|
||||
<a name="talos.resource.definitions.k8s.APIServerEndpoint"></a>
|
||||
|
||||
### APIServerEndpoint
|
||||
APIServerEndpoint holds data for control plane endpoint.
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| host | [string](#string) | | |
|
||||
| port | [uint32](#uint32) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="talos.resource.definitions.k8s.APIServerEndpointsSpec"></a>
|
||||
|
||||
### APIServerEndpointsSpec
|
||||
APIServerEndpointsSpec describes APIServerEndpoints configuration.
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| endpoints | [APIServerEndpoint](#talos.resource.definitions.k8s.APIServerEndpoint) | repeated | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="talos.resource.definitions.k8s.AdmissionControlConfigSpec"></a>
|
||||
|
||||
### AdmissionControlConfigSpec
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user