feat: expose Talos node labels as a machine configuration field
We add the `nodeLabels` key to the machine config to allow users to add node labels to the kubernetes Node object. A controller reads the nodeLabels from the machine config and applies them via the kubernetes API. Older versions of talosctl will throw an unknown keys error if `edit mc` is called on a node with this change. Fixes #6301 Signed-off-by: Philipp Sauter <philipp.sauter@siderolabs.com> Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
This commit is contained in:
parent
c78bbbfda3
commit
e1e340bdd9
@ -148,6 +148,12 @@ message NodeIPSpec {
|
||||
repeated common.NetIP addresses = 1;
|
||||
}
|
||||
|
||||
// NodeLabelSpecSpec represents a label that's attached to a Talos node.
|
||||
message NodeLabelSpecSpec {
|
||||
string key = 1;
|
||||
string value = 2;
|
||||
}
|
||||
|
||||
// NodenameSpec describes Kubernetes nodename.
|
||||
message NodenameSpec {
|
||||
string nodename = 1;
|
||||
|
1
go.mod
1
go.mod
@ -153,6 +153,7 @@ require (
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.4.10 // indirect
|
||||
github.com/adrg/xdg v0.4.0 // indirect
|
||||
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect
|
||||
github.com/benbjohnson/clock v1.1.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
|
1
go.sum
1
go.sum
@ -124,6 +124,7 @@ github.com/aws/aws-sdk-go v1.44.136/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8
|
||||
github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw=
|
||||
github.com/beevik/ntp v0.3.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
|
@ -208,7 +208,23 @@ system
|
||||
```
|
||||
|
||||
> Note: `cgroupsv1` is deprecated and it should be used only for compatibility with workloads which don't support `cgroupsv2` yet.
|
||||
"""
|
||||
|
||||
[notes.nodelabels]
|
||||
title = "Node Labels"
|
||||
description = """\
|
||||
Talos now supports specifying node labels in the machine configuration:
|
||||
|
||||
```yaml
|
||||
machine:
|
||||
nodeLabels:
|
||||
rack: rack1a
|
||||
zone: us-east-1a
|
||||
```
|
||||
|
||||
Changes to the node labels will be applied immediately without `kubelet` restart.
|
||||
|
||||
Talos keeps track of the owned node labels in the `talos.dev/owned-labels` annotation.
|
||||
"""
|
||||
|
||||
[make_deps]
|
||||
|
@ -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/.
|
||||
|
||||
package config
|
||||
package k8s
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -20,16 +20,16 @@ import (
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/network"
|
||||
)
|
||||
|
||||
// K8sAddressFilterController creates NodeAddressFilters based on machine configuration.
|
||||
type K8sAddressFilterController struct{}
|
||||
// AddressFilterController creates NodeAddressFilters based on machine configuration.
|
||||
type AddressFilterController struct{}
|
||||
|
||||
// Name implements controller.Controller interface.
|
||||
func (ctrl *K8sAddressFilterController) Name() string {
|
||||
return "network.K8sAddressFilterController"
|
||||
func (ctrl *AddressFilterController) Name() string {
|
||||
return "k8s.AddressFilterController"
|
||||
}
|
||||
|
||||
// Inputs implements controller.Controller interface.
|
||||
func (ctrl *K8sAddressFilterController) Inputs() []controller.Input {
|
||||
func (ctrl *AddressFilterController) Inputs() []controller.Input {
|
||||
return []controller.Input{
|
||||
{
|
||||
Namespace: config.NamespaceName,
|
||||
@ -41,7 +41,7 @@ func (ctrl *K8sAddressFilterController) Inputs() []controller.Input {
|
||||
}
|
||||
|
||||
// Outputs implements controller.Controller interface.
|
||||
func (ctrl *K8sAddressFilterController) Outputs() []controller.Output {
|
||||
func (ctrl *AddressFilterController) Outputs() []controller.Output {
|
||||
return []controller.Output{
|
||||
{
|
||||
Type: network.NodeAddressFilterType,
|
||||
@ -53,7 +53,7 @@ func (ctrl *K8sAddressFilterController) Outputs() []controller.Output {
|
||||
// Run implements controller.Controller interface.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (ctrl *K8sAddressFilterController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
func (ctrl *AddressFilterController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
@ -3,7 +3,7 @@
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//nolint:dupl
|
||||
package config_test
|
||||
package k8s_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -22,7 +22,7 @@ import (
|
||||
"github.com/siderolabs/go-retry/retry"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
configctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/config"
|
||||
k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s"
|
||||
"github.com/siderolabs/talos/pkg/logging"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/config"
|
||||
@ -53,7 +53,7 @@ func (suite *K8sAddressFilterSuite) SetupTest() {
|
||||
suite.runtime, err = runtime.NewRuntime(suite.state, logging.Wrap(log.Writer()))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Require().NoError(suite.runtime.RegisterController(&configctrl.K8sAddressFilterController{}))
|
||||
suite.Require().NoError(suite.runtime.RegisterController(&k8sctrl.AddressFilterController{}))
|
||||
|
||||
suite.startRuntime()
|
||||
}
|
@ -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/.
|
||||
|
||||
package config
|
||||
package k8s
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -26,16 +26,16 @@ import (
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/k8s"
|
||||
)
|
||||
|
||||
// K8sControlPlaneController manages Kubernetes control plane resources based on configuration.
|
||||
type K8sControlPlaneController struct{}
|
||||
// ControlPlaneController manages Kubernetes control plane resources based on configuration.
|
||||
type ControlPlaneController struct{}
|
||||
|
||||
// Name implements controller.Controller interface.
|
||||
func (ctrl *K8sControlPlaneController) Name() string {
|
||||
return "config.K8sControlPlaneController"
|
||||
func (ctrl *ControlPlaneController) Name() string {
|
||||
return "k8s.ControlPlaneController"
|
||||
}
|
||||
|
||||
// Inputs implements controller.Controller interface.
|
||||
func (ctrl *K8sControlPlaneController) Inputs() []controller.Input {
|
||||
func (ctrl *ControlPlaneController) Inputs() []controller.Input {
|
||||
return []controller.Input{
|
||||
{
|
||||
Namespace: config.NamespaceName,
|
||||
@ -53,7 +53,7 @@ func (ctrl *K8sControlPlaneController) Inputs() []controller.Input {
|
||||
}
|
||||
|
||||
// Outputs implements controller.Controller interface.
|
||||
func (ctrl *K8sControlPlaneController) Outputs() []controller.Output {
|
||||
func (ctrl *ControlPlaneController) Outputs() []controller.Output {
|
||||
return []controller.Output{
|
||||
{
|
||||
Type: k8s.AdmissionControlConfigType,
|
||||
@ -89,7 +89,7 @@ func (ctrl *K8sControlPlaneController) Outputs() []controller.Output {
|
||||
// Run implements controller.Controller interface.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (ctrl *K8sControlPlaneController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
func (ctrl *ControlPlaneController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
@ -158,10 +158,10 @@ func convertVolumes(volumes []talosconfig.VolumeMount) []k8s.ExtraVolume {
|
||||
})
|
||||
}
|
||||
|
||||
func (ctrl *K8sControlPlaneController) manageAPIServerConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
func (ctrl *ControlPlaneController) manageAPIServerConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
var cloudProvider string
|
||||
if cfgProvider.Cluster().ExternalCloudProvider().Enabled() {
|
||||
cloudProvider = "external"
|
||||
cloudProvider = "external" //nolint:goconst
|
||||
}
|
||||
|
||||
advertisedAddress := "$(POD_IP)"
|
||||
@ -188,7 +188,7 @@ func (ctrl *K8sControlPlaneController) manageAPIServerConfig(ctx context.Context
|
||||
})
|
||||
}
|
||||
|
||||
func (ctrl *K8sControlPlaneController) manageAdmissionControlConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
func (ctrl *ControlPlaneController) manageAdmissionControlConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
spec := k8s.AdmissionControlConfigSpec{}
|
||||
|
||||
for _, cfg := range cfgProvider.Cluster().APIServer().AdmissionControl() {
|
||||
@ -207,7 +207,7 @@ func (ctrl *K8sControlPlaneController) manageAdmissionControlConfig(ctx context.
|
||||
})
|
||||
}
|
||||
|
||||
func (ctrl *K8sControlPlaneController) manageAuditPolicyConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
func (ctrl *ControlPlaneController) manageAuditPolicyConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
spec := k8s.AuditPolicyConfigSpec{}
|
||||
|
||||
spec.Config = cfgProvider.Cluster().APIServer().AuditPolicy()
|
||||
@ -219,7 +219,7 @@ func (ctrl *K8sControlPlaneController) manageAuditPolicyConfig(ctx context.Conte
|
||||
})
|
||||
}
|
||||
|
||||
func (ctrl *K8sControlPlaneController) manageControllerManagerConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
func (ctrl *ControlPlaneController) manageControllerManagerConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
var cloudProvider string
|
||||
if cfgProvider.Cluster().ExternalCloudProvider().Enabled() {
|
||||
cloudProvider = "external"
|
||||
@ -241,7 +241,7 @@ func (ctrl *K8sControlPlaneController) manageControllerManagerConfig(ctx context
|
||||
})
|
||||
}
|
||||
|
||||
func (ctrl *K8sControlPlaneController) manageSchedulerConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
func (ctrl *ControlPlaneController) manageSchedulerConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
return r.Modify(ctx, k8s.NewSchedulerConfig(), func(r resource.Resource) error {
|
||||
*r.(*k8s.SchedulerConfig).TypedSpec() = k8s.SchedulerConfigSpec{
|
||||
Enabled: !cfgProvider.Machine().Controlplane().Scheduler().Disabled(),
|
||||
@ -255,7 +255,7 @@ func (ctrl *K8sControlPlaneController) manageSchedulerConfig(ctx context.Context
|
||||
})
|
||||
}
|
||||
|
||||
func (ctrl *K8sControlPlaneController) manageManifestsConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
func (ctrl *ControlPlaneController) manageManifestsConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
dnsServiceIPs, err := cfgProvider.Cluster().Network().DNSServiceIPs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error calculating DNS service IPs: %w", err)
|
||||
@ -311,7 +311,7 @@ func (ctrl *K8sControlPlaneController) manageManifestsConfig(ctx context.Context
|
||||
})
|
||||
}
|
||||
|
||||
func (ctrl *K8sControlPlaneController) manageExtraManifestsConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
func (ctrl *ControlPlaneController) manageExtraManifestsConfig(ctx context.Context, r controller.Runtime, logger *zap.Logger, cfgProvider talosconfig.Provider) error {
|
||||
return r.Modify(ctx, k8s.NewExtraManifestsConfig(), func(r resource.Resource) error {
|
||||
spec := k8s.ExtraManifestsConfigSpec{}
|
||||
|
||||
@ -354,7 +354,7 @@ func (ctrl *K8sControlPlaneController) manageExtraManifestsConfig(ctx context.Co
|
||||
})
|
||||
}
|
||||
|
||||
func (ctrl *K8sControlPlaneController) teardownAll(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
func (ctrl *ControlPlaneController) teardownAll(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//nolint:dupl
|
||||
package config_test
|
||||
package k8s_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -25,7 +25,7 @@ import (
|
||||
"github.com/siderolabs/go-retry/retry"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
configctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/config"
|
||||
k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s"
|
||||
"github.com/siderolabs/talos/pkg/logging"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine"
|
||||
@ -56,7 +56,7 @@ func (suite *K8sControlPlaneSuite) SetupTest() {
|
||||
suite.runtime, err = runtime.NewRuntime(suite.state, logging.Wrap(log.Writer()))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Require().NoError(suite.runtime.RegisterController(&configctrl.K8sControlPlaneController{}))
|
||||
suite.Require().NoError(suite.runtime.RegisterController(&k8sctrl.ControlPlaneController{}))
|
||||
|
||||
suite.startRuntime()
|
||||
}
|
||||
@ -417,7 +417,7 @@ func (suite *K8sControlPlaneSuite) TearDownTest() {
|
||||
suite.state.Destroy(
|
||||
context.Background(),
|
||||
k8s.NewAPIServerConfig().Metadata(),
|
||||
state.WithDestroyOwner("config.K8sControlPlaneController"),
|
||||
state.WithDestroyOwner("k8s.ControlPlaneController"),
|
||||
),
|
||||
)
|
||||
}
|
103
internal/app/machined/pkg/controllers/k8s/node_label_spec.go
Normal file
103
internal/app/machined/pkg/controllers/k8s/node_label_spec.go
Normal file
@ -0,0 +1,103 @@
|
||||
// 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"
|
||||
|
||||
"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"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/config"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/k8s"
|
||||
)
|
||||
|
||||
// NodeLabelSpecController manages k8s.NodeLabelsConfig based on configuration.
|
||||
type NodeLabelSpecController struct{}
|
||||
|
||||
// Name implements controller.Controller interface.
|
||||
func (ctrl *NodeLabelSpecController) Name() string {
|
||||
return "k8s.NodeLabelSpecController"
|
||||
}
|
||||
|
||||
// Inputs implements controller.Controller interface.
|
||||
func (ctrl *NodeLabelSpecController) Inputs() []controller.Input {
|
||||
return []controller.Input{
|
||||
{
|
||||
Namespace: config.NamespaceName,
|
||||
Type: config.MachineConfigType,
|
||||
ID: pointer.To(config.V1Alpha1ID),
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Outputs implements controller.Controller interface.
|
||||
func (ctrl *NodeLabelSpecController) Outputs() []controller.Output {
|
||||
return []controller.Output{
|
||||
{
|
||||
Type: k8s.NodeLabelSpecType,
|
||||
Kind: controller.OutputExclusive,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Run implements controller.Controller interface.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (ctrl *NodeLabelSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-r.EventCh():
|
||||
}
|
||||
|
||||
var nodeLabels map[string]string
|
||||
|
||||
cfg, err := safe.ReaderGet[*config.MachineConfig](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
|
||||
if err != nil {
|
||||
if !state.IsNotFoundError(err) {
|
||||
return fmt.Errorf("error getting config: %w", err)
|
||||
}
|
||||
} else {
|
||||
nodeLabels = cfg.Config().Machine().NodeLabels()
|
||||
}
|
||||
|
||||
for key, value := range nodeLabels {
|
||||
if err = r.Modify(ctx, k8s.NewNodeLabelSpec(key), func(r resource.Resource) error {
|
||||
r.(*k8s.NodeLabelSpec).TypedSpec().Key = key
|
||||
r.(*k8s.NodeLabelSpec).TypedSpec().Value = value
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("error updating node label spec: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
labelSpecs, err := safe.ReaderList[*k8s.NodeLabelSpec](ctx, r, k8s.NewNodeLabelSpec("").Metadata())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting node label specs: %w", err)
|
||||
}
|
||||
|
||||
for iter := safe.IteratorFromList(labelSpecs); iter.Next(); {
|
||||
labelSpec := iter.Value()
|
||||
|
||||
_, touched := nodeLabels[labelSpec.TypedSpec().Key]
|
||||
if touched {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = r.Destroy(ctx, labelSpec.Metadata()); err != nil {
|
||||
return fmt.Errorf("error destroying node label spec: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,274 @@
|
||||
// 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/.
|
||||
|
||||
//nolint:dupl
|
||||
package k8s_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/controller/runtime"
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"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/suite"
|
||||
|
||||
k8sctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s"
|
||||
"github.com/siderolabs/talos/pkg/logging"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/config"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/k8s"
|
||||
)
|
||||
|
||||
type NodeLabelsSuite struct {
|
||||
suite.Suite
|
||||
|
||||
state state.State
|
||||
|
||||
runtime *runtime.Runtime
|
||||
wg sync.WaitGroup
|
||||
|
||||
//nolint:containedctx
|
||||
ctx context.Context
|
||||
ctxCancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) createAndStartRuntime() {
|
||||
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)
|
||||
|
||||
suite.state = state.WrapCore(namespaced.NewState(inmem.Build))
|
||||
|
||||
var err error
|
||||
|
||||
suite.runtime, err = runtime.NewRuntime(suite.state, logging.Wrap(log.Writer()))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Require().NoError(suite.runtime.RegisterController(&k8sctrl.NodeLabelSpecController{}))
|
||||
|
||||
suite.startRuntime()
|
||||
|
||||
suite.setupMachineType()
|
||||
|
||||
suite.createNodename()
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) SetupTest() {
|
||||
suite.createAndStartRuntime()
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) startRuntime() {
|
||||
suite.wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer suite.wg.Done()
|
||||
|
||||
suite.Assert().NoError(suite.runtime.Run(suite.ctx))
|
||||
}()
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) assertResource(
|
||||
md resource.Metadata,
|
||||
check func(res resource.Resource) error,
|
||||
) func() error {
|
||||
return func() error {
|
||||
r, err := suite.state.Get(suite.ctx, md)
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
return retry.ExpectedError(err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return check(r)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) setupMachineType() {
|
||||
machineType := config.NewMachineType()
|
||||
machineType.SetMachineType(machine.TypeControlPlane)
|
||||
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, machineType))
|
||||
}
|
||||
|
||||
func mcWithNodeLabels(labels map[string]string) *config.MachineConfig {
|
||||
return config.NewMachineConfig(
|
||||
&v1alpha1.Config{
|
||||
MachineConfig: &v1alpha1.MachineConfig{
|
||||
MachineNodeLabels: labels,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) createNodeLabelsConfig(labels map[string]string) {
|
||||
mc := mcWithNodeLabels(labels)
|
||||
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, mc))
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) createNodename() {
|
||||
nodeName := k8s.NewNodename(k8s.NamespaceName, k8s.NodenameID)
|
||||
suite.Require().NoError(suite.state.Create(suite.ctx, nodeName))
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) changeNodeLabelsConfig(labels map[string]string) {
|
||||
mc := mcWithNodeLabels(labels)
|
||||
|
||||
oldCfg, err := suite.state.Get(suite.ctx, mc.Metadata())
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
suite.Require().NoError(
|
||||
suite.state.Create(suite.ctx, mc),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
|
||||
mc.Metadata().SetVersion(oldCfg.Metadata().Version())
|
||||
|
||||
suite.Require().NoError(
|
||||
suite.state.Update(suite.ctx, mc),
|
||||
)
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) assertInexistentLabel(expectedLabel string) {
|
||||
suite.Assert().NoError(
|
||||
retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
func() error {
|
||||
md := resource.NewMetadata(
|
||||
k8s.NamespaceName,
|
||||
k8s.NodeLabelSpecType,
|
||||
expectedLabel,
|
||||
resource.VersionUndefined,
|
||||
)
|
||||
|
||||
_, err := suite.state.Get(suite.ctx, md)
|
||||
if err == nil {
|
||||
return retry.ExpectedError(fmt.Errorf("resource should be destroyed: %v", md))
|
||||
}
|
||||
|
||||
if !state.IsNotFoundError(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) assertLabel(expectedLabel, oldValue, expectedValue string) {
|
||||
suite.Assert().NoError(
|
||||
retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
|
||||
func() error {
|
||||
if err := suite.assertResource(
|
||||
resource.NewMetadata(
|
||||
k8s.NamespaceName,
|
||||
k8s.NodeLabelSpecType,
|
||||
expectedLabel,
|
||||
resource.VersionUndefined,
|
||||
),
|
||||
func(res resource.Resource) error {
|
||||
spec := res.(*k8s.NodeLabelSpec).TypedSpec()
|
||||
|
||||
suite.Assert().Equal(
|
||||
expectedLabel,
|
||||
spec.Key,
|
||||
)
|
||||
|
||||
if oldValue != "" && spec.Value == oldValue {
|
||||
return retry.ExpectedError(fmt.Errorf("old value still set: %q", oldValue))
|
||||
}
|
||||
|
||||
suite.Assert().Equal(
|
||||
expectedValue,
|
||||
spec.Value,
|
||||
)
|
||||
|
||||
return nil
|
||||
},
|
||||
)(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) TestAddLabel() {
|
||||
// given
|
||||
expectedLabel := "expectedLabel"
|
||||
expectedValue := "expectedValue"
|
||||
|
||||
// when
|
||||
suite.createNodeLabelsConfig(map[string]string{
|
||||
expectedLabel: expectedValue,
|
||||
})
|
||||
|
||||
// then
|
||||
suite.assertLabel(expectedLabel, "", expectedValue)
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) TestChangeLabel() {
|
||||
// given
|
||||
expectedLabel := "someLabel"
|
||||
oldValue := "oldValue"
|
||||
expectedValue := "newValue"
|
||||
|
||||
// when
|
||||
suite.createNodeLabelsConfig(map[string]string{
|
||||
expectedLabel: oldValue,
|
||||
})
|
||||
|
||||
suite.assertLabel(expectedLabel, "", oldValue)
|
||||
|
||||
suite.changeNodeLabelsConfig(map[string]string{
|
||||
expectedLabel: expectedValue,
|
||||
})
|
||||
|
||||
// then
|
||||
suite.assertLabel(expectedLabel, oldValue, expectedValue)
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) TestDeleteLabel() {
|
||||
// given
|
||||
expectedLabel := "label"
|
||||
expectedValue := "labelValue"
|
||||
|
||||
// when
|
||||
suite.createNodeLabelsConfig(map[string]string{
|
||||
expectedLabel: expectedValue,
|
||||
})
|
||||
suite.assertLabel(expectedLabel, "", expectedValue)
|
||||
|
||||
suite.changeNodeLabelsConfig(map[string]string{})
|
||||
|
||||
// then
|
||||
suite.assertInexistentLabel(expectedLabel)
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) TearDownTest() {
|
||||
suite.T().Log("tear down")
|
||||
|
||||
suite.ctxCancel()
|
||||
|
||||
suite.wg.Wait()
|
||||
}
|
||||
|
||||
func TestNodeLabelsSuite(t *testing.T) {
|
||||
suite.Run(t, new(NodeLabelsSuite))
|
||||
}
|
280
internal/app/machined/pkg/controllers/k8s/node_labels_apply.go
Normal file
280
internal/app/machined/pkg/controllers/k8s/node_labels_apply.go
Normal file
@ -0,0 +1,280 @@
|
||||
// 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"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"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/maps"
|
||||
"github.com/siderolabs/gen/slices"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"github.com/siderolabs/go-retry/retry"
|
||||
"go.uber.org/zap"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/conditions"
|
||||
"github.com/siderolabs/talos/pkg/kubernetes"
|
||||
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/config"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/k8s"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/secrets"
|
||||
)
|
||||
|
||||
// NodeLabelsApplyController watches k8s.NodeLabelSpec's and applies them to the k8s Node object.
|
||||
type NodeLabelsApplyController struct{}
|
||||
|
||||
// Name implements controller.Controller interface.
|
||||
func (ctrl *NodeLabelsApplyController) Name() string {
|
||||
return "k8s.NodeLabelsApplyController"
|
||||
}
|
||||
|
||||
// Inputs implements controller.Controller interface.
|
||||
func (ctrl *NodeLabelsApplyController) Inputs() []controller.Input {
|
||||
return []controller.Input{
|
||||
{
|
||||
Namespace: k8s.NamespaceName,
|
||||
Type: k8s.NodeLabelSpecType,
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
{
|
||||
Namespace: secrets.NamespaceName,
|
||||
Type: secrets.KubernetesRootType,
|
||||
ID: pointer.To(secrets.KubernetesRootID),
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
{
|
||||
Namespace: k8s.NamespaceName,
|
||||
Type: k8s.NodenameType,
|
||||
ID: pointer.To(k8s.NodenameID),
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
{
|
||||
Namespace: config.NamespaceName,
|
||||
Type: config.MachineTypeType,
|
||||
ID: pointer.To(config.MachineTypeID),
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Outputs implements controller.Controller interface.
|
||||
func (ctrl *NodeLabelsApplyController) Outputs() []controller.Output {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run implements controller.Controller interface.
|
||||
func (ctrl *NodeLabelsApplyController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-r.EventCh():
|
||||
}
|
||||
|
||||
if err := ctrl.reconcileWithK8s(ctx, r, logger); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *NodeLabelsApplyController) getNodeLabelSpecs(ctx context.Context, r controller.Runtime) (map[string]string, error) {
|
||||
items, err := safe.ReaderList[*k8s.NodeLabelSpec](ctx, r, resource.NewMetadata(k8s.NamespaceName, k8s.NodeLabelSpecType, "", resource.VersionUndefined))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing node label spec resources: %w", err)
|
||||
}
|
||||
|
||||
result := make(map[string]string, items.Len())
|
||||
|
||||
for iter := safe.IteratorFromList(items); iter.Next(); {
|
||||
result[iter.Value().TypedSpec().Key] = iter.Value().TypedSpec().Value
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (ctrl *NodeLabelsApplyController) getK8sClient(ctx context.Context, r controller.Runtime, logger *zap.Logger) (*kubernetes.Client, error) {
|
||||
machineType, err := safe.ReaderGet[*config.MachineType](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineTypeType, config.MachineTypeID, resource.VersionUndefined))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting machine type: %w", err)
|
||||
}
|
||||
|
||||
if machineType.MachineType().IsControlPlane() {
|
||||
k8sRoot, err := safe.ReaderGet[*secrets.KubernetesRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesRootType, secrets.KubernetesRootID, resource.VersionUndefined))
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to get kubernetes config: %w", err)
|
||||
}
|
||||
|
||||
k8sRootSpec := k8sRoot.TypedSpec()
|
||||
|
||||
return kubernetes.NewTemporaryClientFromPKI(k8sRootSpec.CA, k8sRootSpec.Endpoint)
|
||||
}
|
||||
|
||||
logger.Debug("waiting for kubelet client config", zap.String("file", constants.KubeletKubeconfig))
|
||||
|
||||
if err := conditions.WaitForKubeconfigReady(constants.KubeletKubeconfig).Wait(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return kubernetes.NewClientFromKubeletKubeconfig()
|
||||
}
|
||||
|
||||
func (ctrl *NodeLabelsApplyController) reconcileWithK8s(
|
||||
ctx context.Context,
|
||||
r controller.Runtime,
|
||||
logger *zap.Logger,
|
||||
) error {
|
||||
nodenameResource, err := safe.ReaderGet[*k8s.Nodename](ctx, r, resource.NewMetadata(k8s.NamespaceName, k8s.NodenameType, k8s.NodenameID, resource.VersionUndefined))
|
||||
if err != nil {
|
||||
if state.IsNotFoundError(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
nodename := nodenameResource.TypedSpec().Nodename
|
||||
|
||||
k8sClient, err := ctrl.getK8sClient(ctx, r, logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error building kubernetes client: %w", err)
|
||||
}
|
||||
|
||||
if k8sClient == nil {
|
||||
// not ready yet
|
||||
return nil
|
||||
}
|
||||
|
||||
defer k8sClient.Close() //nolint:errcheck
|
||||
|
||||
nodeLabelSpecs, err := ctrl.getNodeLabelSpecs(ctx, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ctrl.syncLabels(ctx, logger, k8sClient, nodename, nodeLabelSpecs)
|
||||
}
|
||||
|
||||
func (ctrl *NodeLabelsApplyController) syncLabels(
|
||||
ctx context.Context,
|
||||
logger *zap.Logger,
|
||||
k8sClient *kubernetes.Client,
|
||||
nodeName string,
|
||||
nodeLabelSpecs map[string]string,
|
||||
) error {
|
||||
// run several attempts retrying conflict errors
|
||||
return retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).RetryWithContext(ctx, func(ctx context.Context) error {
|
||||
err := ctrl.syncLabelsOnce(ctx, logger, k8sClient, nodeName, nodeLabelSpecs)
|
||||
|
||||
if err != nil && apierrors.IsConflict(err) {
|
||||
return retry.ExpectedError(err)
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (ctrl *NodeLabelsApplyController) syncLabelsOnce(
|
||||
ctx context.Context,
|
||||
logger *zap.Logger,
|
||||
k8sClient *kubernetes.Client,
|
||||
nodeName string,
|
||||
nodeLabelSpecs map[string]string,
|
||||
) error {
|
||||
node, err := k8sClient.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting node: %w", err)
|
||||
}
|
||||
|
||||
if node.Labels == nil {
|
||||
node.Labels = make(map[string]string)
|
||||
}
|
||||
|
||||
ownedJSON := []byte(node.Annotations[constants.AnnotationOwnedLabels])
|
||||
ownedLabels := []string{}
|
||||
|
||||
if len(ownedJSON) > 0 {
|
||||
if err = json.Unmarshal(ownedJSON, &ownedLabels); err != nil {
|
||||
return fmt.Errorf("error unmarshaling owned labels: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
ownedLabelsMap := slices.ToSet(ownedLabels)
|
||||
if ownedLabelsMap == nil {
|
||||
ownedLabelsMap = map[string]struct{}{}
|
||||
}
|
||||
|
||||
ctrl.ApplyLabels(logger, node, ownedLabelsMap, nodeLabelSpecs)
|
||||
|
||||
ownedLabels = maps.Keys(ownedLabelsMap)
|
||||
sort.Strings(ownedLabels)
|
||||
|
||||
if len(ownedLabels) > 0 {
|
||||
ownedJSON, err = json.Marshal(ownedLabels)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshaling owned labels: %w", err)
|
||||
}
|
||||
|
||||
node.Annotations[constants.AnnotationOwnedLabels] = string(ownedJSON)
|
||||
} else {
|
||||
delete(node.Annotations, constants.AnnotationOwnedLabels)
|
||||
}
|
||||
|
||||
_, err = k8sClient.CoreV1().Nodes().Update(ctx, node, metav1.UpdateOptions{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// ApplyLabels performs the inner loop of the node label reconciliation.
|
||||
//
|
||||
// This method is exported for testing purposes.
|
||||
func (ctrl *NodeLabelsApplyController) ApplyLabels(logger *zap.Logger, node *v1.Node, ownedLabels map[string]struct{}, nodeLabelSpecs map[string]string) {
|
||||
// set labels from the spec
|
||||
for key, value := range nodeLabelSpecs {
|
||||
currentValue, exists := node.Labels[key]
|
||||
|
||||
// label is not set on the node yet, so take it over
|
||||
if !exists {
|
||||
node.Labels[key] = value
|
||||
ownedLabels[key] = struct{}{}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// no change to the label, skip it
|
||||
if currentValue == value {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, owned := ownedLabels[key]; !owned {
|
||||
logger.Debug("skipping label update, label is not owned", zap.String("key", key), zap.String("value", value))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
node.Labels[key] = value
|
||||
}
|
||||
|
||||
// remove labels which are owned but are not in the spec
|
||||
for key := range ownedLabels {
|
||||
if _, exists := nodeLabelSpecs[key]; !exists {
|
||||
delete(node.Labels, key)
|
||||
delete(ownedLabels, key)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
// 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 (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/siderolabs/gen/maps"
|
||||
"github.com/siderolabs/gen/slices"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/zap/zaptest"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s"
|
||||
)
|
||||
|
||||
func TestApplyLabels(t *testing.T) {
|
||||
ctrl := &k8s.NodeLabelsApplyController{}
|
||||
logger := zaptest.NewLogger(t)
|
||||
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
inputLabels map[string]string
|
||||
ownedLabels []string
|
||||
labelSpec map[string]string
|
||||
|
||||
expectedLabels map[string]string
|
||||
expectedOwnedLabels []string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
inputLabels: map[string]string{},
|
||||
ownedLabels: []string{},
|
||||
labelSpec: map[string]string{},
|
||||
|
||||
expectedLabels: map[string]string{},
|
||||
expectedOwnedLabels: []string{},
|
||||
},
|
||||
{
|
||||
name: "initial set labels",
|
||||
inputLabels: map[string]string{
|
||||
"hostname": "foo",
|
||||
},
|
||||
ownedLabels: []string{},
|
||||
labelSpec: map[string]string{
|
||||
"label1": "value1",
|
||||
"label2": "value2",
|
||||
},
|
||||
|
||||
expectedLabels: map[string]string{
|
||||
"hostname": "foo",
|
||||
"label1": "value1",
|
||||
"label2": "value2",
|
||||
},
|
||||
expectedOwnedLabels: []string{
|
||||
"label1",
|
||||
"label2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update owned labels",
|
||||
inputLabels: map[string]string{
|
||||
"hostname": "foo",
|
||||
"label1": "value1",
|
||||
"label2": "value2",
|
||||
},
|
||||
ownedLabels: []string{
|
||||
"label1",
|
||||
"label2",
|
||||
},
|
||||
labelSpec: map[string]string{
|
||||
"label1": "value3",
|
||||
},
|
||||
|
||||
expectedLabels: map[string]string{
|
||||
"hostname": "foo",
|
||||
"label1": "value3",
|
||||
},
|
||||
expectedOwnedLabels: []string{
|
||||
"label1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ignore not owned labels",
|
||||
inputLabels: map[string]string{
|
||||
"hostname": "foo",
|
||||
"label1": "value1",
|
||||
"label2": "value2",
|
||||
"label3": "value3",
|
||||
},
|
||||
ownedLabels: []string{
|
||||
"label2",
|
||||
},
|
||||
labelSpec: map[string]string{
|
||||
"label1": "value3",
|
||||
"label2": "value2",
|
||||
},
|
||||
|
||||
expectedLabels: map[string]string{
|
||||
"hostname": "foo",
|
||||
"label1": "value1",
|
||||
"label2": "value2",
|
||||
"label3": "value3",
|
||||
},
|
||||
expectedOwnedLabels: []string{
|
||||
"label2",
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
node := &v1.Node{}
|
||||
node.Labels = tt.inputLabels
|
||||
|
||||
ownedLabels := slices.ToSet(tt.ownedLabels)
|
||||
if ownedLabels == nil {
|
||||
ownedLabels = map[string]struct{}{}
|
||||
}
|
||||
|
||||
ctrl.ApplyLabels(logger, node, ownedLabels, tt.labelSpec)
|
||||
|
||||
newOwnedLabels := maps.Keys(ownedLabels)
|
||||
if newOwnedLabels == nil {
|
||||
newOwnedLabels = []string{}
|
||||
}
|
||||
|
||||
sort.Strings(newOwnedLabels)
|
||||
|
||||
assert.Equal(t, tt.expectedLabels, node.Labels)
|
||||
assert.Equal(t, tt.expectedOwnedLabels, newOwnedLabels)
|
||||
})
|
||||
}
|
||||
}
|
@ -133,6 +133,7 @@ func (r *Runtime) CanApplyImmediate(cfg config.Provider) error {
|
||||
// * .machine.registries (note that auth is not applied immediately, containerd limitation)
|
||||
// * .machine.pods
|
||||
// * .machine.seccompProfiles
|
||||
// * .machine.nodeLabels
|
||||
// * .machine.features.kubernetesTalosAPIAccess
|
||||
newConfig.ConfigDebug = currentConfig.ConfigDebug
|
||||
newConfig.ClusterConfig = currentConfig.ClusterConfig
|
||||
@ -151,6 +152,7 @@ func (r *Runtime) CanApplyImmediate(cfg config.Provider) error {
|
||||
newConfig.MachineConfig.MachineRegistries = currentConfig.MachineConfig.MachineRegistries
|
||||
newConfig.MachineConfig.MachinePods = currentConfig.MachineConfig.MachinePods
|
||||
newConfig.MachineConfig.MachineSeccompProfiles = currentConfig.MachineConfig.MachineSeccompProfiles
|
||||
newConfig.MachineConfig.MachineNodeLabels = currentConfig.MachineConfig.MachineNodeLabels
|
||||
|
||||
if newConfig.MachineConfig.MachineFeatures != nil && currentConfig.MachineConfig.MachineFeatures != nil {
|
||||
newConfig.MachineConfig.MachineFeatures.KubernetesTalosAPIAccessConfig = currentConfig.MachineConfig.MachineFeatures.KubernetesTalosAPIAccessConfig
|
||||
|
@ -85,27 +85,18 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
|
||||
go ctrl.watchMachineConfig(ctx)
|
||||
|
||||
for _, c := range []controller.Controller{
|
||||
&v1alpha1.ServiceController{
|
||||
// V1Events
|
||||
V1Alpha1Events: ctrl.v1alpha1Runtime.Events(),
|
||||
},
|
||||
&timecontrollers.SyncController{
|
||||
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
|
||||
},
|
||||
&cluster.AffiliateMergeController{},
|
||||
&cluster.ConfigController{},
|
||||
&cluster.DiscoveryServiceController{},
|
||||
&cluster.EndpointController{},
|
||||
&cluster.LocalAffiliateController{},
|
||||
&cluster.MemberController{},
|
||||
&cluster.KubernetesPullController{},
|
||||
&cluster.KubernetesPushController{},
|
||||
&cluster.LocalAffiliateController{},
|
||||
&cluster.MemberController{},
|
||||
&cluster.NodeIdentityController{
|
||||
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
|
||||
},
|
||||
&config.MachineTypeController{},
|
||||
&config.K8sAddressFilterController{},
|
||||
&config.K8sControlPlaneController{},
|
||||
&cri.SeccompProfileController{},
|
||||
&cri.SeccompProfileFileController{
|
||||
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
|
||||
@ -125,6 +116,8 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
|
||||
&hardware.SystemInfoController{
|
||||
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
|
||||
},
|
||||
&k8s.AddressFilterController{},
|
||||
&k8s.ControlPlaneController{},
|
||||
&k8s.ControlPlaneStaticPodController{},
|
||||
&k8s.EndpointController{},
|
||||
&k8s.ExtraManifestController{},
|
||||
@ -137,18 +130,20 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
|
||||
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
|
||||
},
|
||||
&k8s.KubeletStaticPodController{},
|
||||
&k8s.ManifestController{},
|
||||
&k8s.ManifestApplyController{},
|
||||
&k8s.NodeIPController{},
|
||||
&k8s.ManifestController{},
|
||||
&k8s.NodeIPConfigController{},
|
||||
&k8s.NodeIPController{},
|
||||
&k8s.NodeLabelSpecController{},
|
||||
&k8s.NodeLabelsApplyController{},
|
||||
&k8s.NodenameController{},
|
||||
&k8s.RenderConfigsStaticPodController{},
|
||||
&k8s.RenderSecretsStaticPodController{},
|
||||
&k8s.StaticPodConfigController{},
|
||||
&k8s.StaticPodServerController{},
|
||||
&kubeaccess.ConfigController{},
|
||||
&kubeaccess.EndpointController{},
|
||||
&kubeaccess.CRDController{},
|
||||
&kubeaccess.EndpointController{},
|
||||
&kubespan.ConfigController{},
|
||||
&kubespan.EndpointController{},
|
||||
&kubespan.IdentityController{},
|
||||
@ -178,8 +173,8 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
|
||||
Cmdline: procfs.ProcCmdline(),
|
||||
},
|
||||
&network.LinkMergeController{},
|
||||
&network.LinkStatusController{},
|
||||
&network.LinkSpecController{},
|
||||
&network.LinkStatusController{},
|
||||
&network.NodeAddressController{},
|
||||
&network.OperatorConfigController{
|
||||
Cmdline: procfs.ProcCmdline(),
|
||||
@ -205,8 +200,8 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
|
||||
Cmdline: procfs.ProcCmdline(),
|
||||
},
|
||||
&network.RouteMergeController{},
|
||||
&network.RouteStatusController{},
|
||||
&network.RouteSpecController{},
|
||||
&network.RouteStatusController{},
|
||||
&network.StatusController{},
|
||||
&network.TimeServerConfigController{
|
||||
Cmdline: procfs.ProcCmdline(),
|
||||
@ -243,17 +238,23 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
|
||||
&runtimecontrollers.MachineStatusPublisherController{
|
||||
V1Alpha1Events: ctrl.v1alpha1Runtime.Events(),
|
||||
},
|
||||
&secrets.APIController{},
|
||||
&secrets.APICertSANsController{},
|
||||
&secrets.APIController{},
|
||||
&secrets.EtcdController{},
|
||||
&secrets.KubeletController{},
|
||||
&secrets.KubernetesController{},
|
||||
&secrets.KubernetesCertSANsController{},
|
||||
&secrets.KubernetesController{},
|
||||
&secrets.RootController{},
|
||||
&secrets.TrustdController{},
|
||||
&siderolink.ManagerController{
|
||||
Cmdline: procfs.ProcCmdline(),
|
||||
},
|
||||
&timecontrollers.SyncController{
|
||||
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
|
||||
},
|
||||
&v1alpha1.ServiceController{
|
||||
V1Alpha1Events: ctrl.v1alpha1Runtime.Events(),
|
||||
},
|
||||
} {
|
||||
if err := ctrl.controllerRuntime.RegisterController(c); err != nil {
|
||||
return err
|
||||
|
@ -92,6 +92,7 @@ func NewState() (*State, error) {
|
||||
&cluster.Member{},
|
||||
&config.MachineConfig{},
|
||||
&config.MachineType{},
|
||||
&k8s.NodeLabelSpec{},
|
||||
&cri.SeccompProfile{},
|
||||
&etcd.Config{},
|
||||
&etcd.PKIStatus{},
|
||||
|
184
internal/integration/api/node-labels.go
Normal file
184
internal/integration/api/node-labels.go
Normal file
@ -0,0 +1,184 @@
|
||||
// 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/.
|
||||
|
||||
//go:build integration_api
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
|
||||
"github.com/siderolabs/talos/internal/integration/base"
|
||||
machineapi "github.com/siderolabs/talos/pkg/machinery/api/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/client"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine"
|
||||
)
|
||||
|
||||
// NodeLabelsSuite verifies updating node labels via machine config.
|
||||
type NodeLabelsSuite struct {
|
||||
base.K8sSuite
|
||||
|
||||
ctx context.Context //nolint:containedctx
|
||||
ctxCancel context.CancelFunc
|
||||
}
|
||||
|
||||
// SuiteName ...
|
||||
func (suite *NodeLabelsSuite) SuiteName() string {
|
||||
return "api.NodeLabelsSuite"
|
||||
}
|
||||
|
||||
// SetupTest ...
|
||||
func (suite *NodeLabelsSuite) SetupTest() {
|
||||
// make sure API calls have timeout
|
||||
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
}
|
||||
|
||||
// TearDownTest ...
|
||||
func (suite *NodeLabelsSuite) TearDownTest() {
|
||||
if suite.ctxCancel != nil {
|
||||
suite.ctxCancel()
|
||||
}
|
||||
}
|
||||
|
||||
// TestUpdateControlPlane verifies node label updates on control plane nodes.
|
||||
func (suite *NodeLabelsSuite) TestUpdateControlPlane() {
|
||||
node := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)
|
||||
|
||||
suite.testUpdate(node, true)
|
||||
}
|
||||
|
||||
// TestUpdateWorker verifies node label updates on worker nodes.
|
||||
func (suite *NodeLabelsSuite) TestUpdateWorker() {
|
||||
node := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)
|
||||
|
||||
suite.testUpdate(node, false)
|
||||
}
|
||||
|
||||
// testUpdate cycles through a set of node label updates reverting the change in the end.
|
||||
func (suite *NodeLabelsSuite) testUpdate(node string, isControlplane bool) {
|
||||
k8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.T().Logf("updating labels on node %q (%q)", node, k8sNode.Name)
|
||||
|
||||
watcher, err := suite.Clientset.CoreV1().Nodes().Watch(suite.ctx, metav1.ListOptions{
|
||||
FieldSelector: "metadata.name=" + k8sNode.Name,
|
||||
Watch: true,
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
defer watcher.Stop()
|
||||
|
||||
const stdLabelName = "kubernetes.io/hostname"
|
||||
|
||||
stdLabelValue := k8sNode.Labels[stdLabelName]
|
||||
|
||||
// set two new labels
|
||||
suite.setNodeLabels(node, map[string]string{
|
||||
"talos.dev/test1": "value1",
|
||||
"talos.dev/test2": "value2",
|
||||
})
|
||||
|
||||
suite.waitUntil(watcher, map[string]string{
|
||||
"talos.dev/test1": "value1",
|
||||
"talos.dev/test2": "value2",
|
||||
})
|
||||
|
||||
// remove one label owned by Talos
|
||||
suite.setNodeLabels(node, map[string]string{
|
||||
"talos.dev/test1": "foo",
|
||||
})
|
||||
|
||||
suite.waitUntil(watcher, map[string]string{
|
||||
"talos.dev/test1": "foo",
|
||||
"talos.dev/test2": "",
|
||||
})
|
||||
|
||||
// on control plane node, try to override a label not owned by Talos
|
||||
if isControlplane {
|
||||
suite.setNodeLabels(node, map[string]string{
|
||||
"talos.dev/test1": "foo2",
|
||||
stdLabelName: "bar",
|
||||
})
|
||||
|
||||
suite.waitUntil(watcher, map[string]string{
|
||||
"talos.dev/test1": "foo2",
|
||||
stdLabelName: stdLabelValue,
|
||||
})
|
||||
}
|
||||
|
||||
// remove all Talos Labels
|
||||
suite.setNodeLabels(node, nil)
|
||||
|
||||
suite.waitUntil(watcher, map[string]string{
|
||||
"talos.dev/test1": "",
|
||||
"talos.dev/test2": "",
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) waitUntil(watcher watch.Interface, expectedLabels map[string]string) {
|
||||
outer:
|
||||
for {
|
||||
select {
|
||||
case ev := <-watcher.ResultChan():
|
||||
k8sNode, ok := ev.Object.(*v1.Node)
|
||||
suite.Require().True(ok, "watch event is not of type v1.Node")
|
||||
|
||||
suite.T().Logf("labels %v", k8sNode.Labels)
|
||||
|
||||
for k, v := range expectedLabels {
|
||||
if v == "" {
|
||||
_, ok := k8sNode.Labels[k]
|
||||
if ok {
|
||||
suite.T().Logf("label %q is still present", k)
|
||||
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
|
||||
if k8sNode.Labels[k] != v {
|
||||
suite.T().Logf("label %q is not %q", k, v)
|
||||
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
case <-suite.ctx.Done():
|
||||
suite.T().Fatal("timeout")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *NodeLabelsSuite) setNodeLabels(nodeIP string, nodeLabels map[string]string) {
|
||||
nodeCtx := client.WithNode(suite.ctx, nodeIP)
|
||||
|
||||
nodeConfig, err := suite.ReadConfigFromNode(nodeCtx)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
nodeConfigRaw, ok := nodeConfig.Raw().(*v1alpha1.Config)
|
||||
suite.Require().True(ok, "node config is not of type v1alpha1.Config")
|
||||
|
||||
nodeConfigRaw.MachineConfig.MachineNodeLabels = nodeLabels
|
||||
|
||||
bytes, err := nodeConfigRaw.Bytes()
|
||||
suite.Require().NoError(err)
|
||||
|
||||
_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{
|
||||
Data: bytes,
|
||||
Mode: machineapi.ApplyConfigurationRequest_NO_REBOOT,
|
||||
})
|
||||
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
|
||||
func init() {
|
||||
allSuites = append(allSuites, new(NodeLabelsSuite))
|
||||
}
|
@ -224,9 +224,9 @@ func (h *Client) LabelNodeAsControlPlane(ctx context.Context, name string, taint
|
||||
}
|
||||
|
||||
// The node may appear to have no labels at first, so we check for the
|
||||
// existence of a well known label to ensure the patch will be successful.
|
||||
// existence of a well known label to ensure that a patch will be successful.
|
||||
if _, found := n.ObjectMeta.Labels[corev1.LabelHostname]; !found {
|
||||
return errors.New("could not find hostname label")
|
||||
return fmt.Errorf("could not find hostname label")
|
||||
}
|
||||
|
||||
oldData, err := json.Marshal(n)
|
||||
@ -268,12 +268,12 @@ func (h *Client) LabelNodeAsControlPlane(ctx context.Context, name string, taint
|
||||
return fmt.Errorf("failed to create two way merge patch: %w", err)
|
||||
}
|
||||
|
||||
if _, err := h.CoreV1().Nodes().Patch(ctx, n.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}); err != nil {
|
||||
if _, err := h.CoreV1().Nodes().Patch(ctx, name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}); err != nil {
|
||||
if apierrors.IsConflict(err) {
|
||||
return fmt.Errorf("unable to update node metadata due to conflict: %w", err)
|
||||
}
|
||||
|
||||
return fmt.Errorf("error patching node %q: %w", n.Name, err)
|
||||
return fmt.Errorf("error patching node %q: %w", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -1281,6 +1281,62 @@ func (x *NodeIPSpec) GetAddresses() []*common.NetIP {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NodeLabelSpecSpec represents a label that's attached to a Talos node.
|
||||
type NodeLabelSpecSpec struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (x *NodeLabelSpecSpec) Reset() {
|
||||
*x = NodeLabelSpecSpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[17]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *NodeLabelSpecSpec) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*NodeLabelSpecSpec) ProtoMessage() {}
|
||||
|
||||
func (x *NodeLabelSpecSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[17]
|
||||
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 NodeLabelSpecSpec.ProtoReflect.Descriptor instead.
|
||||
func (*NodeLabelSpecSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{17}
|
||||
}
|
||||
|
||||
func (x *NodeLabelSpecSpec) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *NodeLabelSpecSpec) GetValue() string {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// NodenameSpec describes Kubernetes nodename.
|
||||
type NodenameSpec struct {
|
||||
state protoimpl.MessageState
|
||||
@ -1294,7 +1350,7 @@ type NodenameSpec struct {
|
||||
func (x *NodenameSpec) Reset() {
|
||||
*x = NodenameSpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[17]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[18]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1307,7 +1363,7 @@ func (x *NodenameSpec) String() string {
|
||||
func (*NodenameSpec) ProtoMessage() {}
|
||||
|
||||
func (x *NodenameSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[17]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[18]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1320,7 +1376,7 @@ func (x *NodenameSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use NodenameSpec.ProtoReflect.Descriptor instead.
|
||||
func (*NodenameSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{17}
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{18}
|
||||
}
|
||||
|
||||
func (x *NodenameSpec) GetNodename() string {
|
||||
@ -1353,7 +1409,7 @@ type SchedulerConfigSpec struct {
|
||||
func (x *SchedulerConfigSpec) Reset() {
|
||||
*x = SchedulerConfigSpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[18]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[19]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1366,7 +1422,7 @@ func (x *SchedulerConfigSpec) String() string {
|
||||
func (*SchedulerConfigSpec) ProtoMessage() {}
|
||||
|
||||
func (x *SchedulerConfigSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[18]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[19]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1379,7 +1435,7 @@ func (x *SchedulerConfigSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use SchedulerConfigSpec.ProtoReflect.Descriptor instead.
|
||||
func (*SchedulerConfigSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{18}
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{19}
|
||||
}
|
||||
|
||||
func (x *SchedulerConfigSpec) GetEnabled() bool {
|
||||
@ -1430,7 +1486,7 @@ type SecretsStatusSpec struct {
|
||||
func (x *SecretsStatusSpec) Reset() {
|
||||
*x = SecretsStatusSpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[19]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[20]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1443,7 +1499,7 @@ func (x *SecretsStatusSpec) String() string {
|
||||
func (*SecretsStatusSpec) ProtoMessage() {}
|
||||
|
||||
func (x *SecretsStatusSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[19]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[20]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1456,7 +1512,7 @@ func (x *SecretsStatusSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use SecretsStatusSpec.ProtoReflect.Descriptor instead.
|
||||
func (*SecretsStatusSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{19}
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{20}
|
||||
}
|
||||
|
||||
func (x *SecretsStatusSpec) GetReady() bool {
|
||||
@ -1485,7 +1541,7 @@ type SingleManifest struct {
|
||||
func (x *SingleManifest) Reset() {
|
||||
*x = SingleManifest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[20]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[21]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1498,7 +1554,7 @@ func (x *SingleManifest) String() string {
|
||||
func (*SingleManifest) ProtoMessage() {}
|
||||
|
||||
func (x *SingleManifest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[20]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[21]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1511,7 +1567,7 @@ func (x *SingleManifest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use SingleManifest.ProtoReflect.Descriptor instead.
|
||||
func (*SingleManifest) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{20}
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{21}
|
||||
}
|
||||
|
||||
func (x *SingleManifest) GetObject() *structpb.Struct {
|
||||
@ -1533,7 +1589,7 @@ type StaticPodServerStatusSpec struct {
|
||||
func (x *StaticPodServerStatusSpec) Reset() {
|
||||
*x = StaticPodServerStatusSpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[21]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[22]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1546,7 +1602,7 @@ func (x *StaticPodServerStatusSpec) String() string {
|
||||
func (*StaticPodServerStatusSpec) ProtoMessage() {}
|
||||
|
||||
func (x *StaticPodServerStatusSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[21]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[22]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1559,7 +1615,7 @@ func (x *StaticPodServerStatusSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use StaticPodServerStatusSpec.ProtoReflect.Descriptor instead.
|
||||
func (*StaticPodServerStatusSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{21}
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{22}
|
||||
}
|
||||
|
||||
func (x *StaticPodServerStatusSpec) GetUrl() string {
|
||||
@ -1581,7 +1637,7 @@ type StaticPodSpec struct {
|
||||
func (x *StaticPodSpec) Reset() {
|
||||
*x = StaticPodSpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[22]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[23]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1594,7 +1650,7 @@ func (x *StaticPodSpec) String() string {
|
||||
func (*StaticPodSpec) ProtoMessage() {}
|
||||
|
||||
func (x *StaticPodSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[22]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[23]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1607,7 +1663,7 @@ func (x *StaticPodSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use StaticPodSpec.ProtoReflect.Descriptor instead.
|
||||
func (*StaticPodSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{22}
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{23}
|
||||
}
|
||||
|
||||
func (x *StaticPodSpec) GetPod() *structpb.Struct {
|
||||
@ -1629,7 +1685,7 @@ type StaticPodStatusSpec struct {
|
||||
func (x *StaticPodStatusSpec) Reset() {
|
||||
*x = StaticPodStatusSpec{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[23]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[24]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1642,7 +1698,7 @@ func (x *StaticPodStatusSpec) String() string {
|
||||
func (*StaticPodStatusSpec) ProtoMessage() {}
|
||||
|
||||
func (x *StaticPodStatusSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[23]
|
||||
mi := &file_resource_definitions_k8s_k8s_proto_msgTypes[24]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1655,7 +1711,7 @@ func (x *StaticPodStatusSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use StaticPodStatusSpec.ProtoReflect.Descriptor instead.
|
||||
func (*StaticPodStatusSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{23}
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{24}
|
||||
}
|
||||
|
||||
func (x *StaticPodStatusSpec) GetPodStatus() *structpb.Struct {
|
||||
@ -1945,70 +2001,74 @@ var file_resource_definitions_k8s_k8s_proto_rawDesc = []byte{
|
||||
0x6f, 0x64, 0x65, 0x49, 0x50, 0x53, 0x70, 0x65, 0x63, 0x12, 0x2b, 0x0a, 0x09, 0x61, 0x64, 0x64,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 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, 0x22, 0x55, 0x0a, 0x0c, 0x4e, 0x6f, 0x64, 0x65, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x76,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68, 0x6f,
|
||||
0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x86, 0x04,
|
||||
0x0a, 0x13, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,
|
||||
0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
|
||||
0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x61, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x61,
|
||||
0x72, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 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, 0x6b, 0x38, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x45,
|
||||
0x78, 0x74, 0x72, 0x61, 0x41, 0x72, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x65,
|
||||
0x78, 0x74, 0x72, 0x61, 0x41, 0x72, 0x67, 0x73, 0x12, 0x50, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x72,
|
||||
0x61, 0x5f, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x2b, 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, 0x6b, 0x38, 0x73,
|
||||
0x2e, 0x45, 0x78, 0x74, 0x72, 0x61, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x0c, 0x65, 0x78,
|
||||
0x74, 0x72, 0x61, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x82, 0x01, 0x0a, 0x15, 0x65,
|
||||
0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4d, 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, 0x6b, 0x38, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65,
|
||||
0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x2e,
|
||||
0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x65, 0x6e, 0x76, 0x69, 0x72,
|
||||
0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x1a,
|
||||
0x3c, 0x0a, 0x0e, 0x45, 0x78, 0x74, 0x72, 0x61, 0x41, 0x72, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72,
|
||||
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
||||
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x47, 0x0a,
|
||||
0x19, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
|
||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x43, 0x0a, 0x11, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74,
|
||||
0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x72,
|
||||
0x65, 0x61, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x61, 0x64,
|
||||
0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x41, 0x0a, 0x0e, 0x53,
|
||||
0x69, 0x6e, 0x67, 0x6c, 0x65, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a,
|
||||
0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2d,
|
||||
0x0a, 0x19, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x50, 0x6f, 0x64, 0x53, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x75,
|
||||
0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x0a,
|
||||
0x0d, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x50, 0x6f, 0x64, 0x53, 0x70, 0x65, 0x63, 0x12, 0x29,
|
||||
0x0a, 0x03, 0x70, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74,
|
||||
0x72, 0x75, 0x63, 0x74, 0x52, 0x03, 0x70, 0x6f, 0x64, 0x22, 0x4d, 0x0a, 0x13, 0x53, 0x74, 0x61,
|
||||
0x74, 0x69, 0x63, 0x50, 0x6f, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x70, 0x65, 0x63,
|
||||
0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6f, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x09, 0x70,
|
||||
0x6f, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x48, 0x5a, 0x46, 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, 0x6b,
|
||||
0x38, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0x3b, 0x0a, 0x11, 0x4e, 0x6f, 0x64, 0x65, 0x4c, 0x61,
|
||||
0x62, 0x65, 0x6c, 0x53, 0x70, 0x65, 0x63, 0x53, 0x70, 0x65, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x6b,
|
||||
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
|
||||
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x22, 0x55, 0x0a, 0x0c, 0x4e, 0x6f, 0x64, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x53,
|
||||
0x70, 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12,
|
||||
0x29, 0x0a, 0x10, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x68, 0x6f, 0x73, 0x74, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x86, 0x04, 0x0a, 0x13, 0x53,
|
||||
0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70,
|
||||
0x65, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05,
|
||||
0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61,
|
||||
0x67, 0x65, 0x12, 0x61, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x61, 0x72, 0x67, 0x73,
|
||||
0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 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, 0x6b, 0x38, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
|
||||
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x45, 0x78, 0x74, 0x72,
|
||||
0x61, 0x41, 0x72, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x65, 0x78, 0x74, 0x72,
|
||||
0x61, 0x41, 0x72, 0x67, 0x73, 0x12, 0x50, 0x0a, 0x0d, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x76,
|
||||
0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 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, 0x6b, 0x38, 0x73, 0x2e, 0x45, 0x78,
|
||||
0x74, 0x72, 0x61, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x72, 0x61,
|
||||
0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x82, 0x01, 0x0a, 0x15, 0x65, 0x6e, 0x76, 0x69,
|
||||
0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65,
|
||||
0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4d, 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, 0x6b, 0x38, 0x73, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
|
||||
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x45, 0x6e, 0x76,
|
||||
0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65,
|
||||
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d,
|
||||
0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x1a, 0x3c, 0x0a, 0x0e,
|
||||
0x45, 0x78, 0x74, 0x72, 0x61, 0x41, 0x72, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
|
||||
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x47, 0x0a, 0x19, 0x45, 0x6e,
|
||||
0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
|
||||
0x02, 0x38, 0x01, 0x22, 0x43, 0x0a, 0x11, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x61, 0x64,
|
||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x61, 0x64, 0x79, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x41, 0x0a, 0x0e, 0x53, 0x69, 0x6e, 0x67,
|
||||
0x6c, 0x65, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x06, 0x6f, 0x62,
|
||||
0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72,
|
||||
0x75, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2d, 0x0a, 0x19, 0x53,
|
||||
0x74, 0x61, 0x74, 0x69, 0x63, 0x50, 0x6f, 0x64, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x3a, 0x0a, 0x0d, 0x53, 0x74,
|
||||
0x61, 0x74, 0x69, 0x63, 0x50, 0x6f, 0x64, 0x53, 0x70, 0x65, 0x63, 0x12, 0x29, 0x0a, 0x03, 0x70,
|
||||
0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63,
|
||||
0x74, 0x52, 0x03, 0x70, 0x6f, 0x64, 0x22, 0x4d, 0x0a, 0x13, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63,
|
||||
0x50, 0x6f, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x36, 0x0a,
|
||||
0x0a, 0x70, 0x6f, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x09, 0x70, 0x6f, 0x64, 0x53,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x48, 0x5a, 0x46, 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, 0x6b, 0x38, 0x73, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -2023,7 +2083,7 @@ func file_resource_definitions_k8s_k8s_proto_rawDescGZIP() []byte {
|
||||
return file_resource_definitions_k8s_k8s_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_resource_definitions_k8s_k8s_proto_msgTypes = make([]protoimpl.MessageInfo, 32)
|
||||
var file_resource_definitions_k8s_k8s_proto_msgTypes = make([]protoimpl.MessageInfo, 33)
|
||||
var file_resource_definitions_k8s_k8s_proto_goTypes = []interface{}{
|
||||
(*APIServerConfigSpec)(nil), // 0: talos.resource.definitions.k8s.APIServerConfigSpec
|
||||
(*AdmissionControlConfigSpec)(nil), // 1: talos.resource.definitions.k8s.AdmissionControlConfigSpec
|
||||
@ -2042,51 +2102,52 @@ var file_resource_definitions_k8s_k8s_proto_goTypes = []interface{}{
|
||||
(*ManifestStatusSpec)(nil), // 14: talos.resource.definitions.k8s.ManifestStatusSpec
|
||||
(*NodeIPConfigSpec)(nil), // 15: talos.resource.definitions.k8s.NodeIPConfigSpec
|
||||
(*NodeIPSpec)(nil), // 16: talos.resource.definitions.k8s.NodeIPSpec
|
||||
(*NodenameSpec)(nil), // 17: talos.resource.definitions.k8s.NodenameSpec
|
||||
(*SchedulerConfigSpec)(nil), // 18: talos.resource.definitions.k8s.SchedulerConfigSpec
|
||||
(*SecretsStatusSpec)(nil), // 19: talos.resource.definitions.k8s.SecretsStatusSpec
|
||||
(*SingleManifest)(nil), // 20: talos.resource.definitions.k8s.SingleManifest
|
||||
(*StaticPodServerStatusSpec)(nil), // 21: talos.resource.definitions.k8s.StaticPodServerStatusSpec
|
||||
(*StaticPodSpec)(nil), // 22: talos.resource.definitions.k8s.StaticPodSpec
|
||||
(*StaticPodStatusSpec)(nil), // 23: talos.resource.definitions.k8s.StaticPodStatusSpec
|
||||
nil, // 24: talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry
|
||||
nil, // 25: talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntry
|
||||
nil, // 26: talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntry
|
||||
nil, // 27: talos.resource.definitions.k8s.ControllerManagerConfigSpec.EnvironmentVariablesEntry
|
||||
nil, // 28: talos.resource.definitions.k8s.ExtraManifest.ExtraHeadersEntry
|
||||
nil, // 29: talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntry
|
||||
nil, // 30: talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntry
|
||||
nil, // 31: talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntry
|
||||
(*structpb.Struct)(nil), // 32: google.protobuf.Struct
|
||||
(*common.NetIP)(nil), // 33: common.NetIP
|
||||
(*proto.Mount)(nil), // 34: talos.resource.definitions.proto.Mount
|
||||
(*NodeLabelSpecSpec)(nil), // 17: talos.resource.definitions.k8s.NodeLabelSpecSpec
|
||||
(*NodenameSpec)(nil), // 18: talos.resource.definitions.k8s.NodenameSpec
|
||||
(*SchedulerConfigSpec)(nil), // 19: talos.resource.definitions.k8s.SchedulerConfigSpec
|
||||
(*SecretsStatusSpec)(nil), // 20: talos.resource.definitions.k8s.SecretsStatusSpec
|
||||
(*SingleManifest)(nil), // 21: talos.resource.definitions.k8s.SingleManifest
|
||||
(*StaticPodServerStatusSpec)(nil), // 22: talos.resource.definitions.k8s.StaticPodServerStatusSpec
|
||||
(*StaticPodSpec)(nil), // 23: talos.resource.definitions.k8s.StaticPodSpec
|
||||
(*StaticPodStatusSpec)(nil), // 24: talos.resource.definitions.k8s.StaticPodStatusSpec
|
||||
nil, // 25: talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry
|
||||
nil, // 26: talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntry
|
||||
nil, // 27: talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntry
|
||||
nil, // 28: talos.resource.definitions.k8s.ControllerManagerConfigSpec.EnvironmentVariablesEntry
|
||||
nil, // 29: talos.resource.definitions.k8s.ExtraManifest.ExtraHeadersEntry
|
||||
nil, // 30: talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntry
|
||||
nil, // 31: talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntry
|
||||
nil, // 32: talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntry
|
||||
(*structpb.Struct)(nil), // 33: google.protobuf.Struct
|
||||
(*common.NetIP)(nil), // 34: common.NetIP
|
||||
(*proto.Mount)(nil), // 35: talos.resource.definitions.proto.Mount
|
||||
}
|
||||
var file_resource_definitions_k8s_k8s_proto_depIdxs = []int32{
|
||||
24, // 0: talos.resource.definitions.k8s.APIServerConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry
|
||||
25, // 0: talos.resource.definitions.k8s.APIServerConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry
|
||||
10, // 1: talos.resource.definitions.k8s.APIServerConfigSpec.extra_volumes:type_name -> talos.resource.definitions.k8s.ExtraVolume
|
||||
25, // 2: talos.resource.definitions.k8s.APIServerConfigSpec.environment_variables:type_name -> talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntry
|
||||
26, // 2: talos.resource.definitions.k8s.APIServerConfigSpec.environment_variables:type_name -> talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntry
|
||||
2, // 3: talos.resource.definitions.k8s.AdmissionControlConfigSpec.config:type_name -> talos.resource.definitions.k8s.AdmissionPluginSpec
|
||||
32, // 4: talos.resource.definitions.k8s.AdmissionPluginSpec.configuration:type_name -> google.protobuf.Struct
|
||||
32, // 5: talos.resource.definitions.k8s.AuditPolicyConfigSpec.config:type_name -> google.protobuf.Struct
|
||||
26, // 6: talos.resource.definitions.k8s.ControllerManagerConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntry
|
||||
33, // 4: talos.resource.definitions.k8s.AdmissionPluginSpec.configuration:type_name -> google.protobuf.Struct
|
||||
33, // 5: talos.resource.definitions.k8s.AuditPolicyConfigSpec.config:type_name -> google.protobuf.Struct
|
||||
27, // 6: talos.resource.definitions.k8s.ControllerManagerConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntry
|
||||
10, // 7: talos.resource.definitions.k8s.ControllerManagerConfigSpec.extra_volumes:type_name -> talos.resource.definitions.k8s.ExtraVolume
|
||||
27, // 8: talos.resource.definitions.k8s.ControllerManagerConfigSpec.environment_variables:type_name -> talos.resource.definitions.k8s.ControllerManagerConfigSpec.EnvironmentVariablesEntry
|
||||
33, // 9: talos.resource.definitions.k8s.EndpointSpec.addresses:type_name -> common.NetIP
|
||||
28, // 10: talos.resource.definitions.k8s.ExtraManifest.extra_headers:type_name -> talos.resource.definitions.k8s.ExtraManifest.ExtraHeadersEntry
|
||||
28, // 8: talos.resource.definitions.k8s.ControllerManagerConfigSpec.environment_variables:type_name -> talos.resource.definitions.k8s.ControllerManagerConfigSpec.EnvironmentVariablesEntry
|
||||
34, // 9: talos.resource.definitions.k8s.EndpointSpec.addresses:type_name -> common.NetIP
|
||||
29, // 10: talos.resource.definitions.k8s.ExtraManifest.extra_headers:type_name -> talos.resource.definitions.k8s.ExtraManifest.ExtraHeadersEntry
|
||||
8, // 11: talos.resource.definitions.k8s.ExtraManifestsConfigSpec.extra_manifests:type_name -> talos.resource.definitions.k8s.ExtraManifest
|
||||
29, // 12: talos.resource.definitions.k8s.KubeletConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntry
|
||||
34, // 13: talos.resource.definitions.k8s.KubeletConfigSpec.extra_mounts:type_name -> talos.resource.definitions.proto.Mount
|
||||
32, // 14: talos.resource.definitions.k8s.KubeletConfigSpec.extra_config:type_name -> google.protobuf.Struct
|
||||
34, // 15: talos.resource.definitions.k8s.KubeletSpecSpec.extra_mounts:type_name -> talos.resource.definitions.proto.Mount
|
||||
32, // 16: talos.resource.definitions.k8s.KubeletSpecSpec.config:type_name -> google.protobuf.Struct
|
||||
20, // 17: talos.resource.definitions.k8s.ManifestSpec.items:type_name -> talos.resource.definitions.k8s.SingleManifest
|
||||
33, // 18: talos.resource.definitions.k8s.NodeIPSpec.addresses:type_name -> common.NetIP
|
||||
30, // 19: talos.resource.definitions.k8s.SchedulerConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntry
|
||||
30, // 12: talos.resource.definitions.k8s.KubeletConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntry
|
||||
35, // 13: talos.resource.definitions.k8s.KubeletConfigSpec.extra_mounts:type_name -> talos.resource.definitions.proto.Mount
|
||||
33, // 14: talos.resource.definitions.k8s.KubeletConfigSpec.extra_config:type_name -> google.protobuf.Struct
|
||||
35, // 15: talos.resource.definitions.k8s.KubeletSpecSpec.extra_mounts:type_name -> talos.resource.definitions.proto.Mount
|
||||
33, // 16: talos.resource.definitions.k8s.KubeletSpecSpec.config:type_name -> google.protobuf.Struct
|
||||
21, // 17: talos.resource.definitions.k8s.ManifestSpec.items:type_name -> talos.resource.definitions.k8s.SingleManifest
|
||||
34, // 18: talos.resource.definitions.k8s.NodeIPSpec.addresses:type_name -> common.NetIP
|
||||
31, // 19: talos.resource.definitions.k8s.SchedulerConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntry
|
||||
10, // 20: talos.resource.definitions.k8s.SchedulerConfigSpec.extra_volumes:type_name -> talos.resource.definitions.k8s.ExtraVolume
|
||||
31, // 21: talos.resource.definitions.k8s.SchedulerConfigSpec.environment_variables:type_name -> talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntry
|
||||
32, // 22: talos.resource.definitions.k8s.SingleManifest.object:type_name -> google.protobuf.Struct
|
||||
32, // 23: talos.resource.definitions.k8s.StaticPodSpec.pod:type_name -> google.protobuf.Struct
|
||||
32, // 24: talos.resource.definitions.k8s.StaticPodStatusSpec.pod_status:type_name -> google.protobuf.Struct
|
||||
32, // 21: talos.resource.definitions.k8s.SchedulerConfigSpec.environment_variables:type_name -> talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntry
|
||||
33, // 22: talos.resource.definitions.k8s.SingleManifest.object:type_name -> google.protobuf.Struct
|
||||
33, // 23: talos.resource.definitions.k8s.StaticPodSpec.pod:type_name -> google.protobuf.Struct
|
||||
33, // 24: talos.resource.definitions.k8s.StaticPodStatusSpec.pod_status:type_name -> google.protobuf.Struct
|
||||
25, // [25:25] is the sub-list for method output_type
|
||||
25, // [25:25] is the sub-list for method input_type
|
||||
25, // [25:25] is the sub-list for extension type_name
|
||||
@ -2305,7 +2366,7 @@ func file_resource_definitions_k8s_k8s_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_k8s_k8s_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*NodenameSpec); i {
|
||||
switch v := v.(*NodeLabelSpecSpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2317,7 +2378,7 @@ func file_resource_definitions_k8s_k8s_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_k8s_k8s_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SchedulerConfigSpec); i {
|
||||
switch v := v.(*NodenameSpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2329,7 +2390,7 @@ func file_resource_definitions_k8s_k8s_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_k8s_k8s_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SecretsStatusSpec); i {
|
||||
switch v := v.(*SchedulerConfigSpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2341,7 +2402,7 @@ func file_resource_definitions_k8s_k8s_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_k8s_k8s_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SingleManifest); i {
|
||||
switch v := v.(*SecretsStatusSpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2353,7 +2414,7 @@ func file_resource_definitions_k8s_k8s_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_k8s_k8s_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StaticPodServerStatusSpec); i {
|
||||
switch v := v.(*SingleManifest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2365,7 +2426,7 @@ func file_resource_definitions_k8s_k8s_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_k8s_k8s_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StaticPodSpec); i {
|
||||
switch v := v.(*StaticPodServerStatusSpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -2377,6 +2438,18 @@ func file_resource_definitions_k8s_k8s_proto_init() {
|
||||
}
|
||||
}
|
||||
file_resource_definitions_k8s_k8s_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StaticPodSpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_resource_definitions_k8s_k8s_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*StaticPodStatusSpec); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@ -2395,7 +2468,7 @@ func file_resource_definitions_k8s_k8s_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_resource_definitions_k8s_k8s_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 32,
|
||||
NumMessages: 33,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
@ -1373,6 +1373,53 @@ func (m *NodeIPSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *NodeLabelSpecSpec) 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 *NodeLabelSpecSpec) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *NodeLabelSpecSpec) 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.Value) > 0 {
|
||||
i -= len(m.Value)
|
||||
copy(dAtA[i:], m.Value)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Value)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if len(m.Key) > 0 {
|
||||
i -= len(m.Key)
|
||||
copy(dAtA[i:], m.Key)
|
||||
i = encodeVarint(dAtA, i, uint64(len(m.Key)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *NodenameSpec) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
@ -2376,6 +2423,26 @@ func (m *NodeIPSpec) SizeVT() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *NodeLabelSpecSpec) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Key)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
l = len(m.Value)
|
||||
if l > 0 {
|
||||
n += 1 + l + sov(uint64(l))
|
||||
}
|
||||
if m.unknownFields != nil {
|
||||
n += len(m.unknownFields)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *NodenameSpec) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@ -6214,6 +6281,121 @@ func (m *NodeIPSpec) UnmarshalVT(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *NodeLabelSpecSpec) 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: NodeLabelSpecSpec: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: NodeLabelSpecSpec: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Key", 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.Key = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Value", 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.Value = string(dAtA[iNdEx:postIndex])
|
||||
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 *NodenameSpec) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
|
@ -66,6 +66,7 @@ type MachineConfig interface {
|
||||
Logging() Logging
|
||||
Kernel() Kernel
|
||||
SeccompProfiles() []SeccompProfile
|
||||
NodeLabels() NodeLabels
|
||||
}
|
||||
|
||||
// SeccompProfile defines the requirements for a config that pertains to seccomp
|
||||
@ -75,6 +76,9 @@ type SeccompProfile interface {
|
||||
Value() map[string]interface{}
|
||||
}
|
||||
|
||||
// NodeLabels defines the labels that should be set on a node.
|
||||
type NodeLabels map[string]string
|
||||
|
||||
// Disk represents the options available for partitioning, formatting, and
|
||||
// mounting extra disks.
|
||||
type Disk interface {
|
||||
|
@ -68,6 +68,11 @@ func (m *MachineSeccompProfile) Value() map[string]interface{} {
|
||||
return m.MachineSeccompProfileValue.Object
|
||||
}
|
||||
|
||||
// NodeLabels implements the config.Provider interface.
|
||||
func (m *MachineConfig) NodeLabels() config.NodeLabels {
|
||||
return m.MachineNodeLabels
|
||||
}
|
||||
|
||||
// Cluster implements the config.Provider interface.
|
||||
func (c *Config) Cluster() config.ClusterConfig {
|
||||
if c.ClusterConfig == nil {
|
||||
|
@ -830,6 +830,12 @@ type MachineConfig struct {
|
||||
// examples:
|
||||
// - value: machineSeccompExample
|
||||
MachineSeccompProfiles []*MachineSeccompProfile `yaml:"seccompProfiles,omitempty" talos:"omitonlyifnil"`
|
||||
// description: |
|
||||
// Configures the node labels for the machine.
|
||||
// examples:
|
||||
// - name: node labels example.
|
||||
// value: 'map[string]string{"exampleLabel": "exampleLabelValue"}'
|
||||
MachineNodeLabels map[string]string `yaml:"nodeLabels,omitempty"`
|
||||
}
|
||||
|
||||
// MachineSeccompProfile defines seccomp profiles for the machine.
|
||||
|
@ -145,7 +145,7 @@ func init() {
|
||||
FieldName: "machine",
|
||||
},
|
||||
}
|
||||
MachineConfigDoc.Fields = make([]encoder.Doc, 22)
|
||||
MachineConfigDoc.Fields = make([]encoder.Doc, 23)
|
||||
MachineConfigDoc.Fields[0].Name = "type"
|
||||
MachineConfigDoc.Fields[0].Type = "string"
|
||||
MachineConfigDoc.Fields[0].Note = ""
|
||||
@ -313,6 +313,13 @@ func init() {
|
||||
MachineConfigDoc.Fields[21].Comments[encoder.LineComment] = "Configures the seccomp profiles for the machine."
|
||||
|
||||
MachineConfigDoc.Fields[21].AddExample("", machineSeccompExample)
|
||||
MachineConfigDoc.Fields[22].Name = "nodeLabels"
|
||||
MachineConfigDoc.Fields[22].Type = "map[string]string"
|
||||
MachineConfigDoc.Fields[22].Note = ""
|
||||
MachineConfigDoc.Fields[22].Description = "Configures the node labels for the machine."
|
||||
MachineConfigDoc.Fields[22].Comments[encoder.LineComment] = "Configures the node labels for the machine."
|
||||
|
||||
MachineConfigDoc.Fields[22].AddExample("node labels example.", map[string]string{"exampleLabel": "exampleLabelValue"})
|
||||
|
||||
MachineSeccompProfileDoc.Type = "MachineSeccompProfile"
|
||||
MachineSeccompProfileDoc.Comments[encoder.LineComment] = "MachineSeccompProfile defines seccomp profiles for the machine."
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1/machine"
|
||||
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||
"github.com/siderolabs/talos/pkg/machinery/kubelet"
|
||||
"github.com/siderolabs/talos/pkg/machinery/labels"
|
||||
"github.com/siderolabs/talos/pkg/machinery/nethelpers"
|
||||
)
|
||||
|
||||
@ -257,6 +258,10 @@ func (c *Config) Validate(mode config.RuntimeMode, options ...config.ValidationO
|
||||
}
|
||||
}
|
||||
|
||||
if err := labels.Validate(c.MachineConfig.MachineNodeLabels); err != nil {
|
||||
result = multierror.Append(result, fmt.Errorf("invalid machine node labels: %w", err))
|
||||
}
|
||||
|
||||
if c.Machine().Features().KubernetesTalosAPIAccess().Enabled() && !c.Machine().Features().RBACEnabled() {
|
||||
result = multierror.Append(result, fmt.Errorf("feature API RBAC should be enabled when Kubernetes Talos API Access feature is enabled"))
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package v1alpha1_test
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/siderolabs/crypto/x509"
|
||||
@ -1198,6 +1199,31 @@ func TestValidate(t *testing.T) {
|
||||
},
|
||||
expectedError: "1 error occurred:\n\t* feature Kubernetes Talos API Access can only be enabled on control plane machines\n\n",
|
||||
},
|
||||
{
|
||||
name: "NodeLabels",
|
||||
config: &v1alpha1.Config{
|
||||
ConfigVersion: "v1alpha1",
|
||||
MachineConfig: &v1alpha1.MachineConfig{
|
||||
MachineType: "worker",
|
||||
MachineNodeLabels: map[string]string{
|
||||
"/foo": "bar",
|
||||
"key": "value",
|
||||
"talos.dev/foo": "bar",
|
||||
"@!": "#$",
|
||||
"123@.dev/": "456",
|
||||
"a/b/c": strings.Repeat("a", 64),
|
||||
},
|
||||
},
|
||||
ClusterConfig: &v1alpha1.ClusterConfig{
|
||||
ControlPlane: &v1alpha1.ControlPlaneConfig{
|
||||
Endpoint: &v1alpha1.Endpoint{
|
||||
endpointURL,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: "1 error occurred:\n\t* invalid machine node labels: 6 errors occurred:\n\t* prefix cannot be empty: \"/foo\"\n\t* prefix \"123@.dev\" is invalid: domain doesn't match required format: \"123@.dev\"\n\t* name \"@!\" is invalid\n\t* label value \"#$\" is invalid\n\t* invalid format: too many slashes: \"a/b/c\"\n\t* label value length exceeds limit of 63: \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n\n\n\n", //nolint:lll
|
||||
},
|
||||
} {
|
||||
test := test
|
||||
|
||||
|
@ -1410,6 +1410,13 @@ func (in *MachineConfig) DeepCopyInto(out *MachineConfig) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if in.MachineNodeLabels != nil {
|
||||
in, out := &in.MachineNodeLabels, &out.MachineNodeLabels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -603,6 +603,9 @@ const (
|
||||
// AnnotationStaticPodConfigFileVersion is the annotation key for the static pod configuration file version.
|
||||
AnnotationStaticPodConfigFileVersion = "talos.dev/config-file-version"
|
||||
|
||||
// AnnotationOwnedLabels is the annotation key for the list of node labels owned by Talos.
|
||||
AnnotationOwnedLabels = "talos.dev/owned-labels"
|
||||
|
||||
// DefaultNTPServer is the NTP server to use if not configured explicitly.
|
||||
//
|
||||
// TODO: Once we get naming sorted we need to apply for a project specific address
|
||||
|
132
pkg/machinery/labels/validate.go
Normal file
132
pkg/machinery/labels/validate.go
Normal file
@ -0,0 +1,132 @@
|
||||
// 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 labels contains adapter label validation functions from Kubernetes.
|
||||
//
|
||||
// We want to avoid dependency of machinery on Kubernetes packages.
|
||||
package labels
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/siderolabs/gen/maps"
|
||||
)
|
||||
|
||||
// Validate validates that a set of labels are correctly defined.
|
||||
func Validate(labels map[string]string) error {
|
||||
var multiErr *multierror.Error
|
||||
|
||||
keys := maps.Keys(labels)
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
if err := ValidateQualifiedName(k); err != nil {
|
||||
multiErr = multierror.Append(multiErr, err)
|
||||
}
|
||||
|
||||
if err := ValidateLabelValue(labels[k]); err != nil {
|
||||
multiErr = multierror.Append(multiErr, err)
|
||||
}
|
||||
}
|
||||
|
||||
return multiErr.ErrorOrNil()
|
||||
}
|
||||
|
||||
const (
|
||||
dns1123LabelFmt string = "[a-z0-9]([-a-z0-9]*[a-z0-9])?"
|
||||
dns1123SubdomainFmt string = dns1123LabelFmt + "(\\." + dns1123LabelFmt + ")*"
|
||||
dns1123SubdomainMaxLength int = 253
|
||||
)
|
||||
|
||||
var dns1123SubdomainRegexp = regexp.MustCompile("^" + dns1123SubdomainFmt + "$")
|
||||
|
||||
// ValidateDNS1123Subdomain tests for a string that conforms to the definition of a
|
||||
// subdomain in DNS (RFC 1123).
|
||||
func ValidateDNS1123Subdomain(value string) error {
|
||||
if len(value) > dns1123SubdomainMaxLength {
|
||||
return fmt.Errorf("domain name length exceeds limit of %d: %q", dns1123SubdomainMaxLength, value)
|
||||
}
|
||||
|
||||
if !dns1123SubdomainRegexp.MatchString(value) {
|
||||
return fmt.Errorf("domain doesn't match required format: %q", value)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
qnameCharFmt string = "[A-Za-z0-9]"
|
||||
qnameExtCharFmt string = "[-A-Za-z0-9_.]"
|
||||
qualifiedNameFmt string = "(" + qnameCharFmt + qnameExtCharFmt + "*)?" + qnameCharFmt
|
||||
qualifiedNameMaxLength int = 63
|
||||
)
|
||||
|
||||
var qualifiedNameRegexp = regexp.MustCompile("^" + qualifiedNameFmt + "$")
|
||||
|
||||
// ValidateQualifiedName tests whether the value passed is what Kubernetes calls a
|
||||
// "qualified name".
|
||||
//
|
||||
// This is a format used in various places throughout the
|
||||
// system. If the value is not valid, a list of error strings is returned.
|
||||
// Otherwise an empty list (or nil) is returned.
|
||||
func ValidateQualifiedName(value string) error {
|
||||
parts := strings.Split(value, "/")
|
||||
|
||||
var name string
|
||||
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
name = parts[0]
|
||||
case 2:
|
||||
var prefix string
|
||||
|
||||
prefix, name = parts[0], parts[1]
|
||||
|
||||
if len(prefix) == 0 {
|
||||
return fmt.Errorf("prefix cannot be empty: %q", value)
|
||||
} else if err := ValidateDNS1123Subdomain(prefix); err != nil {
|
||||
return fmt.Errorf("prefix %q is invalid: %v", prefix, err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("invalid format: too many slashes: %q", value)
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(name) == 0:
|
||||
return fmt.Errorf("name cannot be empty: %q", value)
|
||||
case len(name) > qualifiedNameMaxLength:
|
||||
return fmt.Errorf("name is too long: %q (limit is %d)", value, qualifiedNameMaxLength)
|
||||
case !qualifiedNameRegexp.MatchString(name):
|
||||
return fmt.Errorf("name %q is invalid", name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
labelValueFmt string = "(" + qualifiedNameFmt + ")?"
|
||||
labelValueMaxLength int = 63
|
||||
)
|
||||
|
||||
var labelValueRegexp = regexp.MustCompile("^" + labelValueFmt + "$")
|
||||
|
||||
// ValidateLabelValue tests whether the value passed is a valid label value.
|
||||
//
|
||||
// If the value is not valid, a list of error strings is returned.
|
||||
// Otherwise an empty list (or nil) is returned.
|
||||
func ValidateLabelValue(value string) error {
|
||||
if len(value) > labelValueMaxLength {
|
||||
return fmt.Errorf("label value length exceeds limit of %d: %q", labelValueMaxLength, value)
|
||||
}
|
||||
|
||||
if !labelValueRegexp.MatchString(value) {
|
||||
return fmt.Errorf("label value %q is invalid", value)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
57
pkg/machinery/labels/validate_test.go
Normal file
57
pkg/machinery/labels/validate_test.go
Normal file
@ -0,0 +1,57 @@
|
||||
// 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 labels_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/labels"
|
||||
)
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
labels map[string]string
|
||||
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
labels: map[string]string{
|
||||
"talos.dev/label": "value",
|
||||
"foo": "bar",
|
||||
"kubernetes.io/hostname": "hostname1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid",
|
||||
labels: map[string]string{
|
||||
"345@.345/label": "value",
|
||||
"foo_": "bar",
|
||||
"/foo": "bar",
|
||||
"a/b/c": "bar",
|
||||
"kubernetes.io/hostname": "hostname1_",
|
||||
strings.Repeat("a", 64): "bar",
|
||||
"bar": strings.Repeat("a", 64),
|
||||
},
|
||||
expectedError: "7 errors occurred:\n\t* prefix cannot be empty: \"/foo\"\n\t* prefix \"345@.345\" is invalid: domain doesn't match required format: \"345@.345\"\n\t* invalid format: too many slashes: \"a/b/c\"\n\t* name is too long: \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" (limit is 63)\n\t* label value length exceeds limit of 63: \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n\t* name \"foo_\" is invalid\n\t* label value \"hostname1_\" is invalid\n\n", //nolint:lll
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := labels.Validate(tt.labels)
|
||||
if tt.expectedError != "" {
|
||||
assert.EqualError(t, err, tt.expectedError)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -16,9 +16,6 @@ import (
|
||||
"github.com/siderolabs/talos/pkg/machinery/proto"
|
||||
)
|
||||
|
||||
//nolint:lll
|
||||
//go:generate deep-copy -type AdmissionControlConfigSpec -type APIServerConfigSpec -type AuditPolicyConfigSpec -type ConfigStatusSpec -type ControllerManagerConfigSpec -type EndpointSpec -type ExtraManifestsConfigSpec -type KubeletLifecycleSpec -type KubeletSpecSpec -type ManifestSpec -type ManifestStatusSpec -type BootstrapManifestsConfigSpec -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 .
|
||||
|
||||
// AdmissionControlConfigType is type of AdmissionControlConfig resource.
|
||||
const AdmissionControlConfigType = resource.Type("AdmissionControlConfigs.kubernetes.talos.dev")
|
||||
|
||||
|
@ -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 ConfigStatusSpec -type ControllerManagerConfigSpec -type EndpointSpec -type ExtraManifestsConfigSpec -type KubeletLifecycleSpec -type KubeletSpecSpec -type ManifestSpec -type ManifestStatusSpec -type BootstrapManifestsConfigSpec -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 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
|
||||
|
||||
@ -72,6 +72,20 @@ func (o AuditPolicyConfigSpec) DeepCopy() AuditPolicyConfigSpec {
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of BootstrapManifestsConfigSpec.
|
||||
func (o BootstrapManifestsConfigSpec) DeepCopy() BootstrapManifestsConfigSpec {
|
||||
var cp BootstrapManifestsConfigSpec = o
|
||||
if o.PodCIDRs != nil {
|
||||
cp.PodCIDRs = make([]string, len(o.PodCIDRs))
|
||||
copy(cp.PodCIDRs, o.PodCIDRs)
|
||||
}
|
||||
if o.ProxyArgs != nil {
|
||||
cp.ProxyArgs = make([]string, len(o.ProxyArgs))
|
||||
copy(cp.ProxyArgs, o.ProxyArgs)
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of ConfigStatusSpec.
|
||||
func (o ConfigStatusSpec) DeepCopy() ConfigStatusSpec {
|
||||
var cp ConfigStatusSpec = o
|
||||
@ -196,17 +210,9 @@ func (o ManifestStatusSpec) DeepCopy() ManifestStatusSpec {
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of BootstrapManifestsConfigSpec.
|
||||
func (o BootstrapManifestsConfigSpec) DeepCopy() BootstrapManifestsConfigSpec {
|
||||
var cp BootstrapManifestsConfigSpec = o
|
||||
if o.PodCIDRs != nil {
|
||||
cp.PodCIDRs = make([]string, len(o.PodCIDRs))
|
||||
copy(cp.PodCIDRs, o.PodCIDRs)
|
||||
}
|
||||
if o.ProxyArgs != nil {
|
||||
cp.ProxyArgs = make([]string, len(o.ProxyArgs))
|
||||
copy(cp.ProxyArgs, o.ProxyArgs)
|
||||
}
|
||||
// DeepCopy generates a deep copy of NodeLabelSpecSpec.
|
||||
func (o NodeLabelSpecSpec) DeepCopy() NodeLabelSpecSpec {
|
||||
var cp NodeLabelSpecSpec = o
|
||||
return cp
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,9 @@ 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 .
|
||||
|
||||
// NamespaceName contains resources supporting Kubernetes components on all node types.
|
||||
const NamespaceName resource.Namespace = "k8s"
|
||||
|
||||
|
75
pkg/machinery/resources/k8s/node_label_spec.go
Normal file
75
pkg/machinery/resources/k8s/node_label_spec.go
Normal file
@ -0,0 +1,75 @@
|
||||
// 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 (
|
||||
"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"
|
||||
)
|
||||
|
||||
// NodeLabelSpecType is the type.
|
||||
const NodeLabelSpecType = resource.Type("NodeLabelSpecs.k8s.talos.dev")
|
||||
|
||||
// NodeLabelSpecSpec represents a label that's attached to a Talos node.
|
||||
//
|
||||
//gotagsrewrite:gen
|
||||
type NodeLabelSpecSpec struct {
|
||||
Key string `yaml:"key" protobuf:"1"`
|
||||
Value string `yaml:"value" protobuf:"2"`
|
||||
}
|
||||
|
||||
// NodeLabelSpec ...
|
||||
type NodeLabelSpec = typed.Resource[NodeLabelSpecSpec, NodeLabelSpecRD]
|
||||
|
||||
// NewNodeLabelSpec initializes a NodeLabel resource.
|
||||
func NewNodeLabelSpec(id resource.ID) *NodeLabelSpec {
|
||||
return typed.NewResource[NodeLabelSpecSpec, NodeLabelSpecRD](
|
||||
resource.NewMetadata(NamespaceName, NodeLabelSpecType, id, resource.VersionUndefined),
|
||||
NodeLabelSpecSpec{},
|
||||
)
|
||||
}
|
||||
|
||||
// NewPopulatedNodeLabelSpec initializes a NodeLabel resource and populates it.
|
||||
func NewPopulatedNodeLabelSpec(id resource.ID, key, value string, createdByTalos bool) *NodeLabelSpec {
|
||||
return typed.NewResource[NodeLabelSpecSpec, NodeLabelSpecRD](
|
||||
resource.NewMetadata(NamespaceName, NodeLabelSpecType, id, resource.VersionUndefined),
|
||||
NodeLabelSpecSpec{
|
||||
Key: key,
|
||||
Value: value,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// NodeLabelSpecRD provides auxiliary methods for NodeLabel.
|
||||
type NodeLabelSpecRD struct{}
|
||||
|
||||
// ResourceDefinition implements meta.ResourceDefinitionProvider interface.
|
||||
func (NodeLabelSpecRD) ResourceDefinition(resource.Metadata, NodeLabelSpecSpec) meta.ResourceDefinitionSpec {
|
||||
return meta.ResourceDefinitionSpec{
|
||||
Type: NodeLabelSpecType,
|
||||
Aliases: []resource.Type{},
|
||||
DefaultNamespace: NamespaceName,
|
||||
Sensitivity: meta.Sensitive,
|
||||
PrintColumns: []meta.PrintColumn{
|
||||
{
|
||||
Name: "Value",
|
||||
JSONPath: "{.value}",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterDefaultTypes()
|
||||
|
||||
err := protobuf.RegisterDynamic[NodeLabelSpecSpec](NodeLabelSpecType, &NodeLabelSpec{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
@ -106,6 +106,7 @@ description: Talos gRPC API reference.
|
||||
- [ManifestStatusSpec](#talos.resource.definitions.k8s.ManifestStatusSpec)
|
||||
- [NodeIPConfigSpec](#talos.resource.definitions.k8s.NodeIPConfigSpec)
|
||||
- [NodeIPSpec](#talos.resource.definitions.k8s.NodeIPSpec)
|
||||
- [NodeLabelSpecSpec](#talos.resource.definitions.k8s.NodeLabelSpecSpec)
|
||||
- [NodenameSpec](#talos.resource.definitions.k8s.NodenameSpec)
|
||||
- [SchedulerConfigSpec](#talos.resource.definitions.k8s.SchedulerConfigSpec)
|
||||
- [SchedulerConfigSpec.EnvironmentVariablesEntry](#talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntry)
|
||||
@ -1970,6 +1971,22 @@ NodeIPSpec holds the Node IP specification.
|
||||
|
||||
|
||||
|
||||
<a name="talos.resource.definitions.k8s.NodeLabelSpecSpec"></a>
|
||||
|
||||
### NodeLabelSpecSpec
|
||||
NodeLabelSpecSpec represents a label that's attached to a Talos node.
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| key | [string](#string) | | |
|
||||
| value | [string](#string) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="talos.resource.definitions.k8s.NodenameSpec"></a>
|
||||
|
||||
### NodenameSpec
|
||||
|
@ -400,6 +400,10 @@ seccompProfiles:
|
||||
value:
|
||||
defaultAction: SCMP_ACT_LOG
|
||||
{{< /highlight >}}</details> | |
|
||||
|`nodeLabels` |map[string]string |Configures the node labels for the machine. <details><summary>Show example(s)</summary>{{< highlight yaml >}}
|
||||
nodeLabels:
|
||||
exampleLabel: exampleLabelValue
|
||||
{{< /highlight >}}</details> | |
|
||||
|
||||
|
||||
|
||||
|
@ -39,6 +39,7 @@ The list of config changes allowed to be applied immediately in Talos {{< releas
|
||||
* `.machine.certCANs`
|
||||
* `.machine.install` (configuration is only applied during install/upgrade)
|
||||
* `.machine.network`
|
||||
* `.machine.nodeLabels`
|
||||
* `.machine.sysfs`
|
||||
* `.machine.sysctls`
|
||||
* `.machine.logging`
|
||||
|
Loading…
x
Reference in New Issue
Block a user