talos/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go
Andrey Smirnov caee24bf61
feat: implement KubeSpan identity controller
Fixes #4138

When KubeSpan is enabled, Talos automatically generates or loads
KubeSpan identity which consists of Wireguard key pair. ULA address is
calculated based on ClusterID and first NIC MAC address.

Some code was borrowed from #3577.

Example:

```
$ talosctl -n 172.20.0.2 get ksi
NODE         NAMESPACE   TYPE               ID      VERSION   ADDRESS                                       PUBLICKEY
172.20.0.2   kubespan    KubeSpanIdentity   local   1         fd71:6e1d:86be:6302:e871:1bff:feb2:ccee/128   Oak2fBEWngBhwslBxDVgnRNHXs88OAp4kjroSX0uqUE=
```

Additional changes:

* `--with-kubespan` flag for `talosctl cluster create` for quick testing
* validate that cluster discovery (and KubeSpan) requires ClusterID and
ClusterSecret.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
Signed-off-by: Seán C McCord <ulexus@gmail.com>
Co-authored-by: Seán C McCord <ulexus@gmail.com>
2021-08-27 18:49:15 +03:00

206 lines
6.8 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package v1alpha2
import (
"context"
"github.com/cosi-project/runtime/pkg/controller"
osruntime "github.com/cosi-project/runtime/pkg/controller/runtime"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/state"
"github.com/talos-systems/go-procfs/procfs"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/cluster"
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/config"
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/files"
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/k8s"
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/kubespan"
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/network"
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/perf"
runtimecontrollers "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/runtime"
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/secrets"
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/time"
"github.com/talos-systems/talos/internal/app/machined/pkg/controllers/v1alpha1"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
"github.com/talos-systems/talos/pkg/logging"
"github.com/talos-systems/talos/pkg/machinery/constants"
configresource "github.com/talos-systems/talos/pkg/resources/config"
)
// Controller implements runtime.V1alpha2Controller.
type Controller struct {
controllerRuntime *osruntime.Runtime
consoleLogLevel zap.AtomicLevel
logger *zap.Logger
v1alpha1Runtime runtime.Runtime
}
// NewController creates Controller.
func NewController(v1alpha1Runtime runtime.Runtime, loggingManager runtime.LoggingManager) (*Controller, error) {
ctrl := &Controller{
v1alpha1Runtime: v1alpha1Runtime,
consoleLogLevel: zap.NewAtomicLevel(),
}
logWriter, err := loggingManager.ServiceLog("controller-runtime").Writer()
if err != nil {
return nil, err
}
ctrl.logger = logging.ZapLogger(
logging.NewLogDestination(logWriter, zapcore.DebugLevel, logging.WithColoredLevels()),
logging.NewLogDestination(logging.StdWriter, ctrl.consoleLogLevel, logging.WithoutTimestamp(), logging.WithoutLogLevels()),
).With(logging.Component("controller-runtime"))
ctrl.controllerRuntime, err = osruntime.NewRuntime(v1alpha1Runtime.State().V1Alpha2().Resources(), ctrl.logger)
return ctrl, err
}
// Run the controller runtime.
func (ctrl *Controller) Run(ctx context.Context) error {
// adjust the log level based on machine configuration
go ctrl.watchMachineConfig(ctx, ctrl.logger)
for _, c := range []controller.Controller{
&v1alpha1.ServiceController{
// V1Events
V1Alpha1Events: ctrl.v1alpha1Runtime.Events(),
},
&time.SyncController{
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
},
&cluster.NodeIdentityController{
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
},
&config.MachineTypeController{},
&config.K8sControlPlaneController{},
&files.EtcFileController{
EtcPath: "/etc",
ShadowPath: constants.SystemEtcPath,
},
&k8s.ControlPlaneStaticPodController{},
&k8s.EndpointController{},
&k8s.ExtraManifestController{},
&k8s.KubeletStaticPodController{},
&k8s.ManifestController{},
&k8s.ManifestApplyController{},
&k8s.NodenameController{},
&k8s.RenderSecretsStaticPodController{},
&kubespan.ConfigController{},
&kubespan.IdentityController{},
&network.AddressConfigController{
Cmdline: procfs.ProcCmdline(),
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
},
&network.AddressMergeController{},
&network.AddressSpecController{},
&network.AddressStatusController{},
&network.EtcFileController{},
&network.HardwareAddrController{},
&network.HostnameConfigController{
Cmdline: procfs.ProcCmdline(),
},
&network.HostnameMergeController{},
&network.HostnameSpecController{
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
},
&network.LinkConfigController{
Cmdline: procfs.ProcCmdline(),
},
&network.LinkMergeController{},
&network.LinkStatusController{},
&network.LinkSpecController{},
&network.NodeAddressController{},
&network.OperatorConfigController{
Cmdline: procfs.ProcCmdline(),
},
&network.OperatorSpecController{
V1alpha1Platform: ctrl.v1alpha1Runtime.State().Platform(),
State: ctrl.v1alpha1Runtime.State().V1Alpha2().Resources(),
},
&network.PlatformConfigController{
V1alpha1Platform: ctrl.v1alpha1Runtime.State().Platform(),
},
&network.ResolverConfigController{
Cmdline: procfs.ProcCmdline(),
},
&network.ResolverMergeController{},
&network.ResolverSpecController{},
&network.RouteConfigController{
Cmdline: procfs.ProcCmdline(),
},
&network.RouteMergeController{},
&network.RouteStatusController{},
&network.RouteSpecController{},
&network.StatusController{},
&network.TimeServerConfigController{
Cmdline: procfs.ProcCmdline(),
},
&network.TimeServerMergeController{},
&network.TimeServerSpecController{},
&perf.StatsController{},
&runtimecontrollers.KernelParamConfigController{},
&runtimecontrollers.KernelParamDefaultsController{
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),
},
&runtimecontrollers.KernelParamSpecController{},
&secrets.APIController{},
&secrets.EtcdController{},
&secrets.KubernetesController{},
&secrets.RootController{},
} {
if err := ctrl.controllerRuntime.RegisterController(c); err != nil {
return err
}
}
return ctrl.controllerRuntime.Run(ctx)
}
// DependencyGraph returns controller-resources dependencies.
func (ctrl *Controller) DependencyGraph() (*controller.DependencyGraph, error) {
return ctrl.controllerRuntime.GetDependencyGraph()
}
func (ctrl *Controller) watchMachineConfig(ctx context.Context, logger *zap.Logger) {
watchCh := make(chan state.Event)
if err := ctrl.v1alpha1Runtime.State().V1Alpha2().Resources().Watch(
ctx,
resource.NewMetadata(configresource.NamespaceName, configresource.MachineConfigType, configresource.V1Alpha1ID, resource.VersionUndefined),
watchCh,
); err != nil {
logger.Warn("error watching machine configuration", zap.Error(err))
return
}
for {
logLevel := zapcore.InfoLevel
select {
case event := <-watchCh:
if event.Type != state.Destroyed {
if event.Resource.(*configresource.MachineConfig).Config().Debug() {
logLevel = zapcore.DebugLevel
}
}
case <-ctx.Done():
return
}
if ctrl.consoleLogLevel.Level() != logLevel {
ctrl.consoleLogLevel.SetLevel(logLevel)
ctrl.logger.Info("setting console log level", zap.Stringer("level", logLevel))
}
}
}