55package controllers
66
77import (
8+ "bytes"
89 "context"
910 "encoding/json"
1011 "errors"
1112 "fmt"
1213 "net"
14+ "slices"
1315 "strconv"
1416 "strings"
1517 "time"
1618
19+ "github.com/Masterminds/semver/v3"
1720 jsonpatch "github.com/evanphx/json-patch"
1821 "github.com/go-logr/logr"
22+ "github.com/siderolabs/go-pointer"
1923 "github.com/siderolabs/talos/pkg/machinery/config"
2024 "github.com/siderolabs/talos/pkg/machinery/config/configloader"
2125 "github.com/siderolabs/talos/pkg/machinery/config/configpatcher"
2226 "github.com/siderolabs/talos/pkg/machinery/config/encoder"
2327 "github.com/siderolabs/talos/pkg/machinery/config/generate"
2428 "github.com/siderolabs/talos/pkg/machinery/config/generate/secrets"
2529 "github.com/siderolabs/talos/pkg/machinery/config/machine"
30+ "github.com/siderolabs/talos/pkg/machinery/config/types/network"
2631 "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1"
2732 "github.com/siderolabs/talos/pkg/machinery/constants"
33+ "github.com/siderolabs/talos/pkg/machinery/nethelpers"
2834 "gopkg.in/yaml.v2"
2935 apierrors "k8s.io/apimachinery/pkg/api/errors"
3036 "k8s.io/apimachinery/pkg/runtime"
@@ -277,6 +283,8 @@ func (r *TalosConfigReconciler) reconcileGenerate(ctx context.Context, tcScope *
277283
278284 machineType , _ := machine .ParseType (config .Spec .GenerateType ) //nolint:errcheck // handle errors later
279285
286+ multiConfigPatches := []string {}
287+
280288 switch {
281289 // Slurp and use user-supplied configs
282290 case config .Spec .GenerateType == "none" :
@@ -291,7 +299,7 @@ func (r *TalosConfigReconciler) reconcileGenerate(ctx context.Context, tcScope *
291299
292300 // Generate configs on the fly
293301 case machineType != machine .TypeUnknown :
294- retData , err = r .genConfigs (ctx , tcScope )
302+ retData , multiConfigPatches , err = r .genConfigs (ctx , tcScope )
295303 if err != nil {
296304 return err
297305 }
@@ -322,10 +330,10 @@ func (r *TalosConfigReconciler) reconcileGenerate(ctx context.Context, tcScope *
322330 }
323331
324332 // Handle strategic merge patches.
325- if len (config .Spec .StrategicPatches ) > 0 {
326- patches := make ([]configpatcher.Patch , 0 , len (config . Spec . StrategicPatches ))
333+ if strategicPatches := slices . AppendSeq (config .Spec .StrategicPatches , slices . Values ( multiConfigPatches )); len ( strategicPatches ) > 0 {
334+ patches := make ([]configpatcher.Patch , 0 , len (strategicPatches ))
327335
328- for _ , strategicPatch := range config . Spec . StrategicPatches {
336+ for _ , strategicPatch := range strategicPatches {
329337 patch , err := configpatcher .LoadPatch ([]byte (strategicPatch ))
330338 if err != nil {
331339 return fmt .Errorf ("failure loading StrategicPatch: %w" , err )
@@ -447,7 +455,7 @@ func (r *TalosConfigReconciler) userConfigs(ctx context.Context, scope *TalosCon
447455}
448456
449457// genConfigs will generate a bootstrap config and a talosconfig to return
450- func (r * TalosConfigReconciler ) genConfigs (ctx context.Context , scope * TalosConfigScope ) (* TalosConfigBundle , error ) {
458+ func (r * TalosConfigReconciler ) genConfigs (ctx context.Context , scope * TalosConfigScope ) (* TalosConfigBundle , [] string , error ) {
451459 retBundle := & TalosConfigBundle {}
452460
453461 // Determine what type of node this is
@@ -456,22 +464,24 @@ func (r *TalosConfigReconciler) genConfigs(ctx context.Context, scope *TalosConf
456464 machineType = machine .TypeWorker
457465 }
458466
467+ patches := []string {}
468+
459469 // Allow user to override default kube version.
460470 // This also handles version being formatted like "vX.Y.Z" instead of without leading 'v'
461471 // TrimPrefix returns the string unchanged if the prefix isn't present.
462472 k8sVersion := constants .DefaultKubernetesVersion
463473 if scope .ConfigOwner .IsMachinePool () {
464474 mp := & expv1.MachinePool {}
465475 if err := runtime .DefaultUnstructuredConverter .FromUnstructured (scope .ConfigOwner .Object , mp ); err != nil {
466- return retBundle , err
476+ return retBundle , patches , err
467477 }
468478 if mp .Spec .Template .Spec .Version != nil {
469479 k8sVersion = strings .TrimPrefix (* mp .Spec .Template .Spec .Version , "v" )
470480 }
471481 } else {
472482 machine := & capiv1.Machine {}
473483 if err := runtime .DefaultUnstructuredConverter .FromUnstructured (scope .ConfigOwner .Object , machine ); err != nil {
474- return retBundle , err
484+ return retBundle , patches , err
475485 }
476486 if machine .Spec .Version != nil {
477487 k8sVersion = strings .TrimPrefix (* machine .Spec .Version , "v" )
@@ -491,15 +501,15 @@ func (r *TalosConfigReconciler) genConfigs(ctx context.Context, scope *TalosConf
491501 var err error
492502 versionContract , err = config .ParseContractFromVersion (scope .Config .Spec .TalosVersion )
493503 if err != nil {
494- return retBundle , fmt .Errorf ("invalid talos-version: %w" , err )
504+ return retBundle , patches , fmt .Errorf ("invalid talos-version: %w" , err )
495505 }
496506 }
497507
498508 genOptions = append (genOptions , generate .WithVersionContract (versionContract ))
499509
500510 secretBundle , err := r .getSecretsBundle (ctx , scope , true , versionContract )
501511 if err != nil {
502- return retBundle , err
512+ return retBundle , patches , err
503513 }
504514
505515 genOptions = append (genOptions , generate .WithSecretsBundle (secretBundle ))
@@ -518,24 +528,24 @@ func (r *TalosConfigReconciler) genConfigs(ctx context.Context, scope *TalosConf
518528 genOptions ... ,
519529 )
520530 if err != nil {
521- return retBundle , err
531+ return retBundle , patches , err
522532 }
523533
524534 // Create the secret with kubernetes certs so a kubeconfig can be generated
525535 if err = r .writeK8sCASecret (ctx , scope , secretBundle .Certs .K8s ); err != nil {
526- return retBundle , err
536+ return retBundle , patches , err
527537 }
528538
529539 tcString , err := genTalosConfigFile (input .ClusterName , secretBundle , nil )
530540 if err != nil {
531- return retBundle , err
541+ return retBundle , patches , err
532542 }
533543
534544 retBundle .TalosConfig = tcString
535545
536546 data , err := input .Config (machineType )
537547 if err != nil {
538- return retBundle , err
548+ return retBundle , patches , err
539549 }
540550
541551 if scope .Cluster .Spec .ClusterNetwork != nil && scope .Cluster .Spec .ClusterNetwork .Pods != nil {
@@ -550,27 +560,48 @@ func (r *TalosConfigReconciler) genConfigs(ctx context.Context, scope *TalosConf
550560 data .RawV1Alpha1 ().MachineConfig .MachineNetwork = & v1alpha1.NetworkConfig {}
551561 }
552562
563+ talosVersion , parseErr := semver .NewVersion (strings .TrimLeft (scope .Config .Spec .TalosVersion , "v" ))
564+
553565 if scope .Config .Spec .Hostname .Source == v1alpha3 .HostnameSourceMachineName {
554- data .RawV1Alpha1 ().MachineConfig .MachineNetwork .NetworkHostname = scope .ConfigOwner .GetName ()
566+ if parseErr == nil && talosVersion .GreaterThanEqual (semver .MustParse ("1.12.0-beta.0" )) {
567+ hostnameCfg , err := newHostnameConfig (scope .ConfigOwner .GetName ())
568+ if err != nil {
569+ return retBundle , patches , err
570+ }
571+
572+ patches = append (patches , hostnameCfg )
573+ } else {
574+ data .RawV1Alpha1 ().MachineConfig .MachineNetwork .NetworkHostname = scope .ConfigOwner .GetName ()
575+ }
555576 }
556577
557578 if scope .Config .Spec .Hostname .Source == v1alpha3 .HostnameSourceInfrastructureName {
558579 machine := & capiv1.Machine {}
559580 if err := runtime .DefaultUnstructuredConverter .FromUnstructured (scope .ConfigOwner .Object , machine ); err != nil {
560- return retBundle , err
581+ return retBundle , patches , err
582+ }
583+
584+ if parseErr == nil && talosVersion .GreaterThanEqual (semver .MustParse ("1.12.0-beta.0" )) {
585+ hostnameCfg , err := newHostnameConfig (machine .Spec .InfrastructureRef .Name )
586+ if err != nil {
587+ return retBundle , patches , err
588+ }
589+
590+ patches = append (patches , hostnameCfg )
591+ } else {
592+ data .RawV1Alpha1 ().MachineConfig .MachineNetwork .NetworkHostname = machine .Spec .InfrastructureRef .Name
561593 }
562- data .RawV1Alpha1 ().MachineConfig .MachineNetwork .NetworkHostname = machine .Spec .InfrastructureRef .Name
563594 }
564595 }
565596
566597 dataOut , err := data .EncodeString (encoder .WithComments (encoder .CommentsDisabled ))
567598 if err != nil {
568- return retBundle , err
599+ return retBundle , patches , err
569600 }
570601
571602 retBundle .BootstrapData = dataOut
572603
573- return retBundle , nil
604+ return retBundle , patches , nil
574605}
575606
576607// MachineToBootstrapMapFunc is a handler.ToRequestsFunc to be used to enqueue
@@ -653,3 +684,15 @@ func (r *TalosConfigReconciler) ClusterToTalosConfigs(ctx context.Context, o cli
653684
654685 return result
655686}
687+
688+ func newHostnameConfig (hostname string ) (string , error ) {
689+ hostnameConfig := network .NewHostnameConfigV1Alpha1 ()
690+ hostnameConfig .ConfigAuto = pointer .To (nethelpers .AutoHostnameKindOff )
691+ hostnameConfig .ConfigHostname = hostname
692+
693+ buf := new (bytes.Buffer )
694+
695+ err := yaml .NewEncoder (buf ).Encode (hostnameConfig )
696+
697+ return buf .String (), err
698+ }
0 commit comments