2019-04-16 19:42:23 -04:00
|
|
|
package node
|
|
|
|
|
|
|
|
|
|
import (
|
2024-02-27 17:43:39 -05:00
|
|
|
"bytes"
|
2019-04-16 19:42:23 -04:00
|
|
|
"context"
|
2024-02-27 17:43:39 -05:00
|
|
|
"net"
|
|
|
|
|
"sort"
|
2019-04-16 19:42:23 -04:00
|
|
|
"strings"
|
|
|
|
|
|
2024-05-06 12:42:27 -04:00
|
|
|
coreclient "github.com/rancher/wrangler/v3/pkg/generated/controllers/core/v1"
|
2019-04-16 19:42:23 -04:00
|
|
|
"github.com/sirupsen/logrus"
|
2025-10-22 04:04:53 -04:00
|
|
|
corev1 "k8s.io/api/core/v1"
|
2024-02-05 15:25:08 -05:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2025-10-22 04:04:53 -04:00
|
|
|
"k8s.io/apimachinery/pkg/fields"
|
|
|
|
|
"k8s.io/client-go/kubernetes"
|
|
|
|
|
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
|
|
|
|
toolscache "k8s.io/client-go/tools/cache"
|
2019-04-16 19:42:23 -04:00
|
|
|
)
|
|
|
|
|
|
2020-10-15 15:06:25 -04:00
|
|
|
func Register(ctx context.Context,
|
|
|
|
|
modCoreDNS bool,
|
2025-10-22 04:04:53 -04:00
|
|
|
coreClient kubernetes.Interface,
|
2020-10-15 15:06:25 -04:00
|
|
|
nodes coreclient.NodeController,
|
|
|
|
|
) error {
|
2025-10-22 04:04:53 -04:00
|
|
|
// create a single-resource watch cache on the coredns configmap so that we
|
|
|
|
|
// don't have to retrieve it from the apiserver every time a node changes.
|
|
|
|
|
lw := toolscache.NewListWatchFromClient(coreClient.CoreV1().RESTClient(), "configmaps", metav1.NamespaceSystem, fields.OneTermEqualSelector(metav1.ObjectNameField, "coredns"))
|
|
|
|
|
informerOpts := toolscache.InformerOptions{ListerWatcher: lw, ObjectType: &corev1.ConfigMap{}, Handler: &toolscache.ResourceEventHandlerFuncs{}}
|
|
|
|
|
indexer, informer := toolscache.NewInformerWithOptions(informerOpts)
|
|
|
|
|
go informer.Run(ctx.Done())
|
|
|
|
|
|
2019-04-16 19:42:23 -04:00
|
|
|
h := &handler{
|
2025-10-22 04:04:53 -04:00
|
|
|
modCoreDNS: modCoreDNS,
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
configMaps: coreClient.CoreV1().ConfigMaps(metav1.NamespaceSystem),
|
|
|
|
|
configMapsStore: indexer,
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
2025-10-22 04:04:53 -04:00
|
|
|
nodes.OnChange(ctx, "node", h.updateHosts)
|
|
|
|
|
nodes.OnRemove(ctx, "node", h.updateHosts)
|
2019-04-16 19:42:23 -04:00
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type handler struct {
|
2025-10-22 04:04:53 -04:00
|
|
|
modCoreDNS bool
|
|
|
|
|
ctx context.Context
|
|
|
|
|
configMaps typedcorev1.ConfigMapInterface
|
|
|
|
|
configMapsStore toolscache.Store
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
|
|
|
|
|
2025-10-22 04:04:53 -04:00
|
|
|
func (h *handler) updateHosts(key string, node *corev1.Node) (*corev1.Node, error) {
|
|
|
|
|
if h.modCoreDNS && node != nil {
|
|
|
|
|
var (
|
|
|
|
|
hostName string
|
|
|
|
|
nodeIPv4 string
|
|
|
|
|
nodeIPv6 string
|
|
|
|
|
)
|
|
|
|
|
for _, address := range node.Status.Addresses {
|
|
|
|
|
switch address.Type {
|
|
|
|
|
case corev1.NodeInternalIP:
|
|
|
|
|
if strings.Contains(address.Address, ":") {
|
|
|
|
|
nodeIPv6 = address.Address
|
|
|
|
|
} else {
|
|
|
|
|
nodeIPv4 = address.Address
|
|
|
|
|
}
|
|
|
|
|
case corev1.NodeHostName:
|
|
|
|
|
hostName = address.Address
|
2024-02-27 17:43:39 -05:00
|
|
|
}
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
2025-10-22 04:04:53 -04:00
|
|
|
if err := h.updateCoreDNSConfigMap(node.Name, hostName, nodeIPv4, nodeIPv6, node.DeletionTimestamp != nil); err != nil {
|
2020-10-15 15:06:25 -04:00
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-27 17:43:39 -05:00
|
|
|
func (h *handler) updateCoreDNSConfigMap(nodeName, hostName, nodeIPv4, nodeIPv6 string, removed bool) error {
|
|
|
|
|
if removed {
|
|
|
|
|
nodeIPv4 = ""
|
|
|
|
|
nodeIPv6 = ""
|
|
|
|
|
} else if nodeIPv4 == "" && nodeIPv6 == "" {
|
2025-04-30 03:43:37 -04:00
|
|
|
logrus.Errorf("No InternalIP addresses found for node %s", nodeName)
|
2020-10-15 15:06:25 -04:00
|
|
|
return nil
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
|
|
|
|
|
2024-02-27 17:43:39 -05:00
|
|
|
nodeNames := nodeName
|
|
|
|
|
if hostName != nodeName {
|
|
|
|
|
nodeNames += " " + hostName
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-22 04:04:53 -04:00
|
|
|
var configMap *corev1.ConfigMap
|
|
|
|
|
if val, ok, err := h.configMapsStore.GetByKey("kube-system/coredns"); err != nil {
|
|
|
|
|
logrus.Errorf("Failed to get coredns ConfigMap from cache: %v", err)
|
|
|
|
|
} else if ok {
|
|
|
|
|
if cm, ok := val.(*corev1.ConfigMap); ok {
|
|
|
|
|
configMap = cm
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if configMap == nil {
|
2020-10-15 15:06:25 -04:00
|
|
|
return nil
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
|
|
|
|
|
2024-02-27 17:43:39 -05:00
|
|
|
addressMap := map[string]string{}
|
2020-10-15 15:06:25 -04:00
|
|
|
|
2024-02-27 17:43:39 -05:00
|
|
|
// extract current entries from hosts file, skipping any entries that are
|
|
|
|
|
// empty, unparsable, or hold an incorrect address for the current node.
|
|
|
|
|
for _, line := range strings.Split(configMap.Data["NodeHosts"], "\n") {
|
|
|
|
|
line, _, _ = strings.Cut(line, "#")
|
2019-04-16 19:42:23 -04:00
|
|
|
if line == "" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
fields := strings.Fields(line)
|
2024-02-27 17:43:39 -05:00
|
|
|
if len(fields) < 2 {
|
2019-04-16 19:42:23 -04:00
|
|
|
logrus.Warnf("Unknown format for hosts line [%s]", line)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
ip := fields[0]
|
2024-02-27 17:43:39 -05:00
|
|
|
if fields[1] == nodeName {
|
|
|
|
|
if strings.Contains(ip, ":") {
|
|
|
|
|
if ip != nodeIPv6 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ip != nodeIPv4 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
|
|
|
|
}
|
2024-02-27 17:43:39 -05:00
|
|
|
names := strings.Join(fields[1:], " ")
|
|
|
|
|
addressMap[ip] = names
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// determine what names we should have for each address family
|
|
|
|
|
var namesv6, namesv4 string
|
|
|
|
|
if nodeIPv4 != "" {
|
|
|
|
|
namesv4 = nodeNames
|
|
|
|
|
}
|
|
|
|
|
if nodeIPv6 != "" {
|
|
|
|
|
namesv6 = nodeNames
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// don't need to do anything if the addresses are in sync
|
|
|
|
|
if !removed && addressMap[nodeIPv4] == namesv4 && addressMap[nodeIPv6] == namesv6 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-22 04:04:53 -04:00
|
|
|
// Something's out of sync, copy the ConfigMap for update and sync the desired entries
|
|
|
|
|
configMap = configMap.DeepCopy()
|
2024-02-27 17:43:39 -05:00
|
|
|
if nodeIPv4 != "" {
|
|
|
|
|
addressMap[nodeIPv4] = namesv4
|
|
|
|
|
}
|
|
|
|
|
if nodeIPv6 != "" {
|
|
|
|
|
addressMap[nodeIPv6] = namesv6
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
|
|
|
|
|
2024-02-27 17:43:39 -05:00
|
|
|
// sort addresses by IP
|
|
|
|
|
addresses := make([]string, 0, len(addressMap))
|
|
|
|
|
for ip := range addressMap {
|
|
|
|
|
addresses = append(addresses, ip)
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
2024-02-27 17:43:39 -05:00
|
|
|
sort.Slice(addresses, func(i, j int) bool {
|
|
|
|
|
return bytes.Compare(net.ParseIP(addresses[i]), net.ParseIP(addresses[j])) < 0
|
|
|
|
|
})
|
2020-10-15 15:06:25 -04:00
|
|
|
|
|
|
|
|
var newHosts string
|
2024-02-27 17:43:39 -05:00
|
|
|
for _, ip := range addresses {
|
|
|
|
|
newHosts += ip + " " + addressMap[ip] + "\n"
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
2024-02-05 15:25:08 -05:00
|
|
|
|
|
|
|
|
if configMap.Data == nil {
|
|
|
|
|
configMap.Data = map[string]string{}
|
|
|
|
|
}
|
2019-04-16 19:42:23 -04:00
|
|
|
configMap.Data["NodeHosts"] = newHosts
|
|
|
|
|
|
2025-10-22 04:04:53 -04:00
|
|
|
if _, err := h.configMaps.Update(h.ctx, configMap, metav1.UpdateOptions{}); err != nil {
|
2020-10-15 15:06:25 -04:00
|
|
|
return err
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var actionType string
|
|
|
|
|
if removed {
|
|
|
|
|
actionType = "Removed"
|
|
|
|
|
} else {
|
2025-10-22 04:04:53 -04:00
|
|
|
actionType = "Synced"
|
2019-04-16 19:42:23 -04:00
|
|
|
}
|
2025-10-22 04:04:53 -04:00
|
|
|
logrus.Infof("%s coredns NodeHosts entries for %s", actionType, nodeName)
|
2020-10-15 15:06:25 -04:00
|
|
|
return nil
|
|
|
|
|
}
|