Big refactor to log/slog

This commit is contained in:
Dan Finneran
2025-01-16 17:45:09 +00:00
parent cb438d289b
commit 2136e69a82
40 changed files with 581 additions and 483 deletions

View File

@@ -4,8 +4,9 @@ import (
"fmt"
"os"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -34,30 +35,34 @@ var kubeKubeadmInit = &cobra.Command{
Long: "The \"init\" subcommand will generate the Kubernetes manifest that will be started by kubeadm through the kubeadm init process",
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
log.SetLogLoggerLevel(log.Level(logLevel))
initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer)
// TODO - A load of text detailing what's actually happening
err := kubevip.ParseEnvironment(&initConfig)
if err != nil {
log.Fatalf("Error parsing environment from config: %v", err)
log.Error("parsing environment", "err", err)
return
}
// TODO - check for certain things VIP/interfaces
if initConfig.Interface == "" {
_ = cmd.Help()
log.Fatalln("No interface is specified for kube-vip to bind to")
log.Error("No interface is specified for kube-vip to bind to")
return
}
if initConfig.VIP == "" && initConfig.Address == "" {
_ = cmd.Help()
log.Fatalln("No address is specified for kube-vip to expose services on")
log.Error("No address is specified for kube-vip to expose services on")
return
}
// Ensure there is an address to generate the CIDR from
if initConfig.VIPCIDR == "" && initConfig.Address != "" {
initConfig.VIPCIDR, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Fatalln(err)
log.Error("generating CIDR", "err", err)
return
}
}
@@ -71,35 +76,40 @@ var kubeKubeadmJoin = &cobra.Command{
Short: "kube-vip join",
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
log.SetLogLoggerLevel(log.Level(logLevel))
initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer)
// TODO - A load of text detailing what's actually happening
err := kubevip.ParseEnvironment(&initConfig)
if err != nil {
log.Fatalf("Error parsing environment from config: %v", err)
log.Error("parsing environment", "err", err)
return
}
// TODO - check for certain things VIP/interfaces
if initConfig.Interface == "" {
_ = cmd.Help()
log.Fatalln("No interface is specified for kube-vip to bind to")
log.Error("No interface is specified for kube-vip to bind to")
return
}
if initConfig.VIP == "" && initConfig.Address == "" {
_ = cmd.Help()
log.Fatalln("No address is specified for kube-vip to expose services on")
log.Error("No address is specified for kube-vip to expose services on")
return
}
if _, err := os.Stat(kubeConfigPath); os.IsNotExist(err) {
log.Fatalf("Unable to find file [%s]", kubeConfigPath)
log.Error("kubeConfig not found", "Path", kubeConfigPath)
return
}
// Ensure there is an address to generate the CIDR from
if initConfig.VIPCIDR == "" && initConfig.Address != "" {
initConfig.VIPCIDR, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Fatalln(err)
log.Error("generating CIDR", "err", err)
return
}
}

View File

@@ -3,8 +3,9 @@ package cmd
import (
"fmt"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)
@@ -41,25 +42,29 @@ var kubeManifestPod = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
var err error
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer)
// TODO - A load of text detailing what's actually happening
if err := kubevip.ParseEnvironment(&initConfig); err != nil {
log.Fatalf("Error parsing environment from config: %v", err)
log.Error("parsing environment", "err", err)
return
}
// Set the logging level for all subsequent functions
log.SetLogLoggerLevel(log.Level(initConfig.Logging))
// The control plane has a requirement for a VIP being specified
if initConfig.EnableControlPlane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) {
_ = cmd.Help()
log.Fatalln("No address is specified for kube-vip to expose services on")
log.Error("No address is specified for kube-vip to expose services on")
return
}
// Ensure there is an address to generate the CIDR from
if initConfig.VIPCIDR == "" && initConfig.Address != "" {
initConfig.VIPCIDR, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Fatalln(err)
log.Error("No interface is specified for kube-vip to bind to")
return
}
}
@@ -74,27 +79,29 @@ var kubeManifestDaemon = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
var err error
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer)
// TODO - A load of text detailing what's actually happening
if err := kubevip.ParseEnvironment(&initConfig); err != nil {
log.Fatalf("error parsing environment config: %v", err)
log.Error("parsing environment", "err", err)
return
}
// TODO - check for certain things VIP/interfaces
// Set the logging level for all subsequent functions
log.SetLogLoggerLevel(log.Level(initConfig.Logging))
// The control plane has a requirement for a VIP being specified
if initConfig.EnableControlPlane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) {
_ = cmd.Help()
log.Fatalln("No address is specified for kube-vip to expose services on")
log.Error("No address is specified for kube-vip to expose services on")
return
}
// Ensure there is an address to generate the CIDR from
if initConfig.VIPCIDR == "" && initConfig.Address != "" {
initConfig.VIPCIDR, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Fatalln(err)
log.Error("No interface is specified for kube-vip to bind to")
return
}
}
@@ -110,24 +117,27 @@ var kubeManifestRbac = &cobra.Command{
var err error
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
log.SetLogLoggerLevel(log.Level(logLevel))
initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer)
// TODO - A load of text detailing what's actually happening
if err := kubevip.ParseEnvironment(&initConfig); err != nil {
log.Fatalf("Error parsing environment from config: %v", err)
log.Error("parsing environment", "err", err)
return
}
// The control plane has a requirement for a VIP being specified
if initConfig.EnableControlPlane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) {
_ = cmd.Help()
log.Fatalln("No address is specified for kube-vip to expose services on")
log.Error("No address is specified for kube-vip to expose services on")
return
}
// Ensure there is an address to generate the CIDR from
if initConfig.VIPCIDR == "" && initConfig.Address != "" {
initConfig.VIPCIDR, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Fatalln(err)
log.Error("generating CIDR", "err", err)
return
}
}

View File

@@ -9,9 +9,10 @@ import (
"strings"
"time"
log "log/slog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/vishvananda/netlink"
@@ -191,16 +192,18 @@ var kubeVipService = &cobra.Command{
Short: "Start the Virtual IP / Load balancer as a service within a Kubernetes cluster",
Run: func(cmd *cobra.Command, args []string) { //nolint TODO
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
log.SetLogLoggerLevel(log.Level(logLevel))
// parse environment variables, these will overwrite anything loaded or flags
err := kubevip.ParseEnvironment(&initConfig)
if err != nil {
log.Fatalln(err)
log.Error("parsing env", "err", err)
return
}
if err := initConfig.CheckInterface(); err != nil {
log.Fatalln(err)
log.Error("checking interface", "err", err)
return
}
// User Environment variables as an option to make manifest clearer
@@ -213,20 +216,23 @@ var kubeVipService = &cobra.Command{
if initConfig.VIPCIDR == "" && initConfig.Address != "" {
initConfig.VIPCIDR, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Fatalln(err)
log.Error("generating CIDR", "err", err)
return
}
}
// Define the new service manager
mgr, err := manager.New(configMap, &initConfig)
if err != nil {
log.Fatalf("%v", err)
log.Error("new manager", "err", err)
return
}
// Start the service manager, this will watch the config Map and construct kube-vip services for it
err = mgr.Start()
if err != nil {
log.Fatalf("%v", err)
log.Error("manager start", "err", err)
return
}
},
}
@@ -238,23 +244,24 @@ var kubeVipManager = &cobra.Command{
// parse environment variables, these will overwrite anything loaded or flags
err := kubevip.ParseEnvironment(&initConfig)
if err != nil {
log.Fatalln(err)
log.Error("parsing environment", "err", err)
return
}
// Ensure there is an address to generate the CIDR from
if initConfig.VIPCIDR == "" && initConfig.Address != "" {
initConfig.VIPCIDR, err = GenerateCidrRange(initConfig.Address)
if err != nil {
log.Fatalln(err)
log.Error("No interface is specified for kube-vip to bind to")
return
}
}
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(initConfig.Logging))
log.SetLogLoggerLevel(log.Level(initConfig.Logging))
// Welome messages
log.Infof("Starting kube-vip.io [%s]", Release.Version)
log.Infof("Build kube-vip.io [%s]", Release.Build)
log.Info("kube-vip.io", "verison", Release.Version, "build", Release.Build)
// start prometheus server
if initConfig.PrometheusHTTPServer != "" {
@@ -282,19 +289,22 @@ var kubeVipManager = &cobra.Command{
}
// Provide configuration to output/logging
log.Infof("namespace [%s], Mode: [%s], Features(s): Control Plane:[%t], Services:[%t]", initConfig.Namespace, mode, initConfig.EnableControlPlane, initConfig.EnableServices)
log.Info("starting", "namespace", initConfig.Namespace, "Mode", mode, "Control Plane", initConfig.EnableControlPlane, "Services", initConfig.EnableServices)
// End if nothing is enabled
if !initConfig.EnableServices && !initConfig.EnableControlPlane {
log.Fatalln("no features are enabled")
log.Error("no features are enabled")
return
}
if !initConfig.EnableARP && strings.Contains(initConfig.VIPCIDR, kubevip.Auto) {
log.Fatalln("auto subnet discovery cannot be used outside ARP mode")
log.Error("auto subnet discovery cannot be used outside ARP mode")
return
}
if strings.Contains(initConfig.VIPCIDR, kubevip.Auto) && initConfig.Address != "" {
log.Fatalln("auto subnet discovery cannot be used if VIP address was provided")
log.Error("auto subnet discovery cannot be used if VIP address was provided")
return
}
// If we're using wireguard then all traffic goes through the wg0 interface
@@ -304,48 +314,55 @@ var kubeVipManager = &cobra.Command{
initConfig.Interface = "wg0"
}
log.Infof("configuring Wireguard networking")
log.Info("configuring Wireguard networking")
l, err := netlink.LinkByName(initConfig.Interface)
if err != nil {
if strings.Contains(err.Error(), "Link not found") {
log.Warnf("interface \"%s\" doesn't exist, attempting to create wireguard interface", initConfig.Interface)
log.Warn("attempting to create wireguard interface", "interface not found", initConfig.Interface)
err = netlink.LinkAdd(&netlink.Wireguard{LinkAttrs: netlink.LinkAttrs{Name: initConfig.Interface}})
if err != nil {
log.Fatalln(err)
log.Error("adding link", "err", err)
return
}
l, err = netlink.LinkByName(initConfig.Interface)
if err != nil {
log.Fatalln(err)
log.Error("finding link", "err", err)
return
}
}
}
err = netlink.LinkSetUp(l)
if err != nil {
log.Fatalln(err)
log.Error("setting link UP", "err", err)
return
}
} else { // if we're not using Wireguard then we'll need to use an actual interface
// Check if the interface needs auto-detecting
if initConfig.Interface == "" {
log.Infof("No interface is specified for VIP in config, auto-detecting default Interface")
log.Info("No interface is specified for VIP in config, auto-detecting default Interface")
defaultIF, err := vip.GetDefaultGatewayInterface()
if err != nil {
_ = cmd.Help()
log.Fatalf("unable to detect default interface -> [%v]", err)
log.Error("detecting interface", "err", err)
return
}
initConfig.Interface = defaultIF.Name
log.Infof("kube-vip will bind to interface [%s]", initConfig.Interface)
log.Info("kube-vip bind", "interface", initConfig.Interface)
go func() {
if err := vip.MonitorDefaultInterface(context.TODO(), defaultIF); err != nil {
log.Fatalf("crash: %s", err.Error())
log.Error("interface monitor", "err", err)
return
}
}()
}
}
// Perform a check on th state of the interface
// Perform a check on the state of the interface
if err := initConfig.CheckInterface(); err != nil {
log.Fatalln(err)
log.Error("checking interface", "err", err)
return
}
// User Environment variables as an option to make manifest clearer
@@ -359,7 +376,8 @@ var kubeVipManager = &cobra.Command{
if providerConfig != "" {
providerAPI, providerProject, err := equinixmetal.GetPacketConfig(providerConfig)
if err != nil {
log.Fatalf("%v", err)
log.Error("retrieving equinix metal config", "err", err)
return
}
initConfig.MetalAPIKey = providerAPI
initConfig.MetalProject = providerProject
@@ -369,7 +387,8 @@ var kubeVipManager = &cobra.Command{
// Define the new service manager
mgr, err := manager.New(configMap, &initConfig)
if err != nil {
log.Fatalf("configuring new Manager error -> %v", err)
log.Error("new manager", "err", err)
return
}
prometheus.MustRegister(mgr.PrometheusCollector()...)
@@ -377,7 +396,8 @@ var kubeVipManager = &cobra.Command{
// Start the service manager, this will watch the config Map and construct kube-vip services for it
err = mgr.Start()
if err != nil {
log.Fatalf("starting new Manager error -> %v", err)
log.Error("start manager", "err", err)
return
}
},
}
@@ -410,15 +430,16 @@ func servePrometheusHTTPServer(ctx context.Context, config PrometheusHTTPServerC
go func() {
if err = srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen:%+s\n", err)
log.Error("prometheus HTTP server", "err", err)
return
}
}()
log.Printf("prometheus HTTP server started")
log.Info("prometheus HTTP server started")
<-ctx.Done()
log.Printf("prometheus HTTP server stopped")
log.Info("prometheus HTTP server stopped")
ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer func() {
@@ -426,7 +447,8 @@ func servePrometheusHTTPServer(ctx context.Context, config PrometheusHTTPServerC
}()
if err = srv.Shutdown(ctxShutDown); err != nil {
log.Fatalf("server Shutdown Failed:%+s", err)
log.Error("shutting down prometheus HTTP server", "err", err)
return
}
if err == http.ErrServerClosed {

View File

@@ -4,10 +4,11 @@ import (
"fmt"
"time"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/k8s"
"github.com/kube-vip/kube-vip/pkg/utils"
"github.com/kube-vip/kube-vip/pkg/vip"
log "github.com/sirupsen/logrus"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
@@ -40,26 +41,26 @@ func (e *Entry) Check() bool {
config, err = k8s.NewRestConfig(adminConfigPath, false, k8sAddr)
// client, err = k8s.NewClientset(adminConfigPath, false, k8sAddr)
if err != nil {
log.Errorf("could not create k8s REST config for external file: %q: %v", adminConfigPath, err)
log.Error("create k8s REST config", "path", adminConfigPath, "err", err)
return false
}
default:
config, err = k8s.NewRestConfig("", true, k8sAddr)
if err != nil {
log.Errorf("could not create k8s REST config %v", err)
log.Error("create k8s REST config", "err", err)
return false
}
}
client, err = k8s.NewClientset(config)
if err != nil {
log.Errorf("failed to create k8s client: %v", err)
log.Error("create k8s client", "err", err)
return false
}
_, err = client.DiscoveryClient.ServerVersion()
if err != nil {
log.Errorf("failed check k8s server version: %s", err)
log.Error("discover k8s version", "err", err)
return false
}
return true

View File

@@ -5,9 +5,10 @@ import (
"fmt"
"time"
log "log/slog"
api "github.com/osrg/gobgp/v3/api"
gobgp "github.com/osrg/gobgp/v3/pkg/server"
log "github.com/sirupsen/logrus"
)
// NewBGPServer takes a configuration and returns a running BGP server instance
@@ -42,7 +43,7 @@ func NewBGPServer(c *Config, peerStateChangeCallback func(*api.WatchEventRespons
if err = b.s.WatchEvent(context.Background(), &api.WatchEventRequest{Peer: &api.WatchEventRequest_Peer{}}, func(r *api.WatchEventResponse) {
if p := r.GetPeer(); p != nil && p.Type == api.WatchEventResponse_PeerEvent_STATE {
log.Infof("[BGP] %s", p.String())
log.Info("[BGP]", "peer", p.String())
if peerStateChangeCallback != nil {
peerStateChangeCallback(p)
}

View File

@@ -3,7 +3,7 @@ package cluster
import (
"sync"
log "github.com/sirupsen/logrus"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/vip"
@@ -34,7 +34,7 @@ func InitCluster(c *kubevip.Config, disableVIP bool) (*Cluster, error) {
Network: networks,
}
log.Debugf("init enable service security: %t", c.EnableServiceSecurity)
log.Debug("service security", "enabled", c.EnableServiceSecurity)
return newCluster, nil
}

View File

@@ -19,7 +19,8 @@ import (
"github.com/packethost/packngo"
log "github.com/sirupsen/logrus"
log "log/slog"
clientv3 "go.etcd.io/etcd/client/v3"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -96,7 +97,7 @@ func NewManager(path string, inCluster bool, port int) (*Manager, error) {
func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server) error {
var err error
log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", c.Namespace, c.LeaseName, c.NodeName)
log.Info("cluster membership", "namespace", c.Namespace, "lock", c.LeaseName, "id", c.NodeName)
// use a Go context so we can tell the leaderelection code when we
// want to step down
@@ -136,7 +137,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *
for i := range cluster.Network {
err = cluster.Network[i].DeleteIP()
if err != nil {
log.Errorf("could not delete virtualIP: %v", err)
log.Error("could not delete virtualIP", "err", err)
}
}
@@ -153,7 +154,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *
if c.ProviderConfig != "" {
key, project, err := equinixmetal.GetPacketConfig(c.ProviderConfig)
if err != nil {
log.Error(err)
log.Error("retrieve Equinix metal config", "err", err)
} else {
// Set the environment variable with the key for the project
os.Setenv("PACKET_AUTH_TOKEN", key)
@@ -163,15 +164,15 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *
}
packetClient, err = packngo.NewClient()
if err != nil {
log.Error(err)
log.Error("create Equinix metal client", "err", err)
}
// We're using Equinix Metal with BGP, populate the Peer information from the API
if c.EnableBGP {
log.Infoln("Looking up the BGP configuration from Equinix Metal")
log.Info("Looking up the BGP configuration from Equinix Metal")
err = equinixmetal.BGPLookup(packetClient, c)
if err != nil {
log.Error(err)
log.Error("retrieve Equinix metal BPG config", "err", err)
}
}
}
@@ -181,7 +182,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *
log.Info("Starting the BGP server to advertise VIP routes to VGP peers")
bgpServer, err = bgp.NewBGPServer(&c.BGPConfig, nil)
if err != nil {
log.Error(err)
log.Error("new BGP server", "err", err)
}
}
@@ -193,7 +194,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *
// As we're leading lets start the vip service
err := cluster.vipService(ctxArp, ctxDNS, c, sm, bgpServer, packetClient)
if err != nil {
log.Errorf("Error starting the VIP service on the leader [%s]", err)
log.Error("starting VIP service on leader", "err", err)
}
},
onStoppedLeading: func() {
@@ -209,22 +210,23 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *
if bgpServer != nil {
err := bgpServer.Close()
if err != nil {
log.Warnf("%v", err)
log.Warn("close BGP server", "err", err)
}
}
for i := range cluster.Network {
err := cluster.Network[i].DeleteIP()
if err != nil {
log.Warnf("%v", err)
log.Warn("delete VIP", "err", err)
}
}
log.Fatal("lost leadership, restarting kube-vip")
log.Error("lost leadership, restarting kube-vip")
panic("") // TODO - we could also return here
},
onNewLeader: func(identity string) {
// we're notified when new leader elected
log.Infof("Node [%s] is assuming leadership of the cluster", identity)
log.Info("New leader", "leader", identity)
},
}
@@ -307,7 +309,7 @@ func (cluster *Cluster) runEtcdLeaderElectionOrDie(ctx context.Context, run *run
func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port uint16) error {
// Use a restartable watcher, as this should help in the event of etcd or timeout issues
log.Infof("Kube-Vip is watching nodes for control-plane labels")
log.Info("Kube-Vip is watching nodes for control-plane labels")
listOptions := metav1.ListOptions{
LabelSelector: "node-role.kubernetes.io/control-plane",
@@ -345,7 +347,7 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port uint16) e
if node.Status.Addresses[x].Type == v1.NodeInternalIP {
err = lb.AddBackend(node.Status.Addresses[x].Address, port)
if err != nil {
log.Errorf("add IPVS backend [%v]", err)
log.Error("add IPVS backend", "err", err)
}
}
}
@@ -360,12 +362,12 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port uint16) e
if node.Status.Addresses[x].Type == v1.NodeInternalIP {
err = lb.RemoveBackend(node.Status.Addresses[x].Address, port)
if err != nil {
log.Errorf("Del IPVS backend [%v]", err)
log.Error("Del IPVS backend", "err", err)
}
}
}
log.Infof("Node [%s] has been deleted", node.Name)
log.Info("Node deleted", "name", node.Name)
case watch.Bookmark:
// Un-used
@@ -380,11 +382,11 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port uint16) e
}
status := statusErr.ErrStatus
log.Errorf("%v", status)
log.Error("watcher", "status", status)
default:
}
}
log.Infoln("Exiting Node watcher")
log.Info("Exiting Node watcher")
return nil
}

View File

@@ -11,6 +11,8 @@ import (
"syscall"
"time"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/backend"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/equinixmetal"
@@ -18,7 +20,6 @@ import (
"github.com/kube-vip/kube-vip/pkg/loadbalancer"
"github.com/kube-vip/kube-vip/pkg/vip"
"github.com/packethost/packngo"
log "github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -41,13 +42,13 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
for i := range cluster.Network {
if cluster.Network[i].IsDDNS() {
if err := cluster.StartDDNS(ctxDNS); err != nil {
log.Error(err)
log.Error(err.Error())
}
}
// start the dns updater if address is dns
if cluster.Network[i].IsDNS() {
log.Infof("starting the DNS updater for the address %s", cluster.Network[i].DNSName())
log.Info("starting the DNS updater", "address", cluster.Network[i].DNSName())
ipUpdater := vip.NewIPUpdater(cluster.Network[i])
ipUpdater.Run(ctxDNS)
}
@@ -63,14 +64,16 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
subnet = subnets[1]
}
if subnet == "" {
log.Fatalf("no subnet provided for IP %s", cluster.Network[i].IP())
log.Error("no subnet provided", "IP", cluster.Network[i].IP())
panic("")
}
if err = cluster.Network[i].SetMask(subnet); err != nil {
log.Fatalf("failed to set mask %s: %s", subnet, err.Error())
log.Error("failed to set mask", "subnet", subnet, "err", err)
panic("")
}
}
if err = cluster.Network[i].AddIP(false); err != nil {
log.Fatalf("%v", err)
log.Error(err.Error())
}
}
@@ -78,10 +81,10 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
// We're not using Equinix Metal with BGP
if !c.EnableBGP {
// Attempt to attach the EIP in the standard manner
log.Debugf("Attaching the Equinix Metal EIP through the API to this host")
log.Debug("Attaching the Equinix Metal EIP through the API to this host")
err = equinixmetal.AttachEIP(packetClient, c, c.NodeName)
if err != nil {
log.Error(err)
log.Error(err.Error())
}
}
}
@@ -89,26 +92,26 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
if c.EnableBGP {
// Lets advertise the VIP over BGP, the host needs to be passed using CIDR notation
cidrVip := fmt.Sprintf("%s/%s", cluster.Network[i].IP(), c.VIPCIDR)
log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip)
log.Debug("Attempting to advertise over BGP", "address", cidrVip)
err = bgpServer.AddHost(cidrVip)
if err != nil {
log.Error(err)
log.Error(err.Error())
}
}
if c.EnableLoadBalancer {
log.Infof("Starting IPVS LoadBalancer")
log.Info("Starting IPVS LoadBalancer")
lb, err := loadbalancer.NewIPVSLB(cluster.Network[i].IP(), c.LoadBalancerPort, c.LoadBalancerForwardingMethod, c.BackendHealthCheckInterval)
if err != nil {
log.Errorf("Error creating IPVS LoadBalancer [%s]", err)
log.Error("Error creating IPVS LoadBalancer", "err", err)
}
go func() {
err = sm.NodeWatcher(lb, c.Port)
if err != nil {
log.Errorf("Error watching node labels [%s]", err)
log.Error("Error watching node labels", "err", err)
}
}()
// Shutdown function that will wait on this signal, unless we call it ourselves
@@ -116,7 +119,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
<-signalChan
err = lb.RemoveIPVSLB()
if err != nil {
log.Errorf("Error stopping IPVS LoadBalancer [%s]", err)
log.Error("Error stopping IPVS LoadBalancer", "err", err)
}
log.Info("Stopping IPVS LoadBalancer")
}()
@@ -131,14 +134,15 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
if isIPv6 {
ndp, err = vip.NewNDPResponder(cluster.Network[i].Interface())
if err != nil {
log.Fatalf("failed to create new NDP Responder")
log.Error("failed to create new NDP Responder")
panic("")
}
}
if ndp != nil {
defer ndp.Close()
}
log.Infof("Gratuitous Arp broadcast will repeat every 3 seconds for [%s/%s]", ipString, cluster.Network[i].Interface())
log.Info("Gratuitous Arp broadcast repeats every 3 seconds", "ip", ipString, "interface", cluster.Network[i].Interface())
for {
select {
case <-ctx.Done(): // if cancel() execute
@@ -167,7 +171,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
ips := []string{}
if nodename != "" {
if ips, err = getNodeIPs(ctxArp, nodename, sm.KubernetesClient); err != nil && !apierrors.IsNotFound(err) {
log.Error("failed to get IP of control-plane node: %w", err)
log.Error("failed to get IP of control-plane nod", "err", err)
}
}
@@ -182,7 +186,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
ips = append(ips, "::1")
}
log.Infof("no IP address found for node - will fallback to use localhost address: %v", ips)
log.Info("no IP address found for node - will fallback to use localhost address", "addresses", ips)
}
for _, ip := range ips {
@@ -224,17 +228,17 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
if entry.Check() {
err = cluster.Network[i].AddIP(true)
if err != nil {
log.Fatalf("error adding IP: %v", err)
log.Error("error adding address", "err", err)
}
if !(*backendMap)[entry] {
log.Infof("added IP: %s", cluster.Network[i].IP())
log.Info("added backend", "ip", cluster.Network[i].IP())
}
err = cluster.Network[i].AddRoute(true)
if err != nil && !errors.Is(err, fs.ErrExist) && !errors.Is(err, syscall.ESRCH) {
log.Warnf("%v", err)
log.Warn(err.Error())
} else if err == nil && !(*backendMap)[entry] {
log.Infof("added route: %s", cluster.Network[i].PrepareRoute().String())
log.Info("added route", "route", cluster.Network[i].PrepareRoute().String())
}
(*backendMap)[entry] = true
@@ -254,9 +258,9 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
if deleteAddress {
err = cluster.Network[i].DeleteRoute()
if err != nil && !errors.Is(err, fs.ErrNotExist) && !errors.Is(err, syscall.ESRCH) {
log.Warnf("error while deleting route: %v", err)
log.Warn("deleting route", "err", err)
} else if err == nil {
log.Infof("deleted route: %s", cluster.Network[i].PrepareRoute().String())
log.Info("deleted route", "route", cluster.Network[i].PrepareRoute().String())
}
isSet, err := cluster.Network[i].IsSet()
@@ -266,9 +270,10 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co
if isSet {
err = cluster.Network[i].DeleteIP()
if err != nil {
log.Fatalf("error deleting IP: %v", err)
log.Error("error deleting IP", "err", err)
panic("")
}
log.Infof("deleted IP: %s", cluster.Network[i].IP())
log.Info("deleted address", "ip", cluster.Network[i].IP())
}
}
}
@@ -315,12 +320,12 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser
err := network.DeleteIP()
if err != nil {
log.Warnf("Attempted to clean existing VIP => %v", err)
log.Warn("Attempted to clean existing VIP", "err", err)
}
if c.EnableRoutingTable && (c.EnableLeaderElection || c.EnableServicesElection) {
err = network.AddRoute(false)
if err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
} else if !c.EnableRoutingTable {
if c.EnableARP {
@@ -333,14 +338,16 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser
subnet = subnets[1]
}
if subnet == "" {
log.Fatalf("no subnet provided for IP %s", cluster.Network[i].IP())
log.Error("no subnet provided for address", "ip", cluster.Network[i].IP())
panic("")
}
if err = network.SetMask(subnet); err != nil {
log.Fatalf("failed to set mask %s: %s", subnet, err.Error())
log.Error("failed to set mask", "subnet", subnet, "err", err)
panic("")
}
}
if err = network.AddIP(false); err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
}
@@ -350,25 +357,26 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser
if vip.IsIPv6(ipString) {
ndp, err = vip.NewNDPResponder(network.Interface())
if err != nil {
log.Fatalf("failed to create new NDP Responder")
log.Error("failed to create new NDP Responder")
panic("")
}
}
go func(ctx context.Context) {
if ndp != nil {
defer ndp.Close()
}
log.Debugf("(svcs) broadcasting ARP update for %s via %s, every %dms", ipString, network.Interface(), c.ArpBroadcastRate)
log.Debug("(svcs) broadcasting ARP update", "ip", ipString, "interface", network.Interface(), "rate", c.ArpBroadcastRate)
for {
select {
case <-ctx.Done(): // if cancel() execute
log.Debugf("(svcs) ending ARP update for %s via %s, every %dms", ipString, network.Interface(), c.ArpBroadcastRate)
log.Debug("(svcs) ending ARP update", "ip", ipString, "interface", network.Interface(), "rate", c.ArpBroadcastRate)
return
default:
cluster.ensureIPAndSendGratuitous(i, ndp)
}
if c.ArpBroadcastRate < 500 {
log.Errorf("arp broadcast rate is [%d], this shouldn't be lower that 300ms (defaulting to 3000)", c.ArpBroadcastRate)
log.Error("arp broadcast rate shouldn't be lower that 300ms (defaulting to 3000)", "currentRate", c.ArpBroadcastRate)
c.ArpBroadcastRate = 3000
}
time.Sleep(time.Duration(c.ArpBroadcastRate) * time.Millisecond)
@@ -379,10 +387,10 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser
if c.EnableBGP && (c.EnableLeaderElection || c.EnableServicesElection) {
// Lets advertise the VIP over BGP, the host needs to be passed using CIDR notation
cidrVip := fmt.Sprintf("%s/%s", network.IP(), c.VIPCIDR)
log.Debugf("(svcs) attempting to advertise the address [%s] over BGP", cidrVip)
log.Debug("(svcs) attempting to advertise over BGP", "address", cidrVip)
err = bgp.AddHost(cidrVip)
if err != nil {
log.Error(err)
log.Error(err.Error())
}
}
}
@@ -396,9 +404,9 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser
if c.EnableRoutingTable {
for i := range cluster.Network {
log.Infof("[VIP] Deleting Route for Virtual IP [%s]", cluster.Network[i].IP())
log.Info("[VIP] Deleting Route for VIP [%s]", "ip", cluster.Network[i].IP())
if err := cluster.Network[i].DeleteRoute(); err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
}
@@ -406,9 +414,9 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser
return
}
for i := range cluster.Network {
log.Infof("[VIP] Releasing the Virtual IP [%s]", cluster.Network[i].IP())
log.Info("[VIP] Deleting VIP", "ip", cluster.Network[i].IP())
if err := cluster.Network[i].DeleteIP(); err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
}
@@ -425,23 +433,23 @@ func (cluster *Cluster) ensureIPAndSendGratuitous(index int, ndp *vip.NdpRespond
// Check if IP is dadfailed
if cluster.Network[index].IsDADFAIL() {
log.Warnf("IP address is in dadfailed state, removing [%s] from interface [%s]", ipString, iface)
log.Warn("IP address is in dadfailed state, removing config", "ip", ipString, "interface", iface)
err := cluster.Network[index].DeleteIP()
if err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
}
// Ensure the address exists on the interface before attempting to ARP
set, err := cluster.Network[index].IsSet()
if err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
if !set {
log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, iface)
log.Warn("Re-applying the VIP configuration", "ip", ipString, "interface", iface)
err = cluster.Network[index].AddIP(false)
if err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
}
@@ -452,7 +460,7 @@ func (cluster *Cluster) ensureIPAndSendGratuitous(index int, ndp *vip.NdpRespond
} else {
err := ndp.SendGratuitous(ipString)
if err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
}
@@ -460,7 +468,7 @@ func (cluster *Cluster) ensureIPAndSendGratuitous(index int, ndp *vip.NdpRespond
// Gratuitous ARP, will broadcast to new MAC <-> IPv4 address
err := vip.ARPSendGratuitous(ipString, iface)
if err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
}

View File

@@ -3,8 +3,9 @@ package cluster
import (
"context"
log "log/slog"
"github.com/packethost/packngo"
log "github.com/sirupsen/logrus"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/kubevip"
@@ -16,7 +17,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro
// Start kube-vip as a single node server
// TODO - Split all this code out as a separate function
log.Infoln("Starting kube-vip as a single node cluster")
log.Info("Starting kube-vip as a single node cluster")
log.Info("This node is assuming leadership of the cluster")
@@ -27,12 +28,12 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro
if !disableVIP {
err := cluster.Network[i].DeleteIP()
if err != nil {
log.Warnf("Attempted to clean existing VIP => %v", err)
log.Warn("Attempted to clean existing VIP", "err", err)
}
err = cluster.Network[i].AddIP(false)
if err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
}
@@ -41,7 +42,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro
// Gratuitous ARP, will broadcast to new MAC <-> IP
err := vip.ARPSendGratuitous(cluster.Network[i].IP(), c.Interface)
if err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
}
}
@@ -51,16 +52,16 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro
if !disableVIP {
for i := range cluster.Network {
log.Infof("[VIP] Releasing the Virtual IP [%s]", cluster.Network[i].IP())
log.Info("[VIP] Releasing the VIP", "address", cluster.Network[i].IP())
err := cluster.Network[i].DeleteIP()
if err != nil {
log.Warnf("%v", err)
log.Warn(err.Error())
}
}
}
close(cluster.completed)
}()
log.Infoln("Started Load Balancer and Virtual IP")
log.Info("Started Load Balancer and Virtual IP")
return nil
}

View File

@@ -3,10 +3,11 @@ package equinixmetal
import (
"fmt"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/packethost/packngo"
log "github.com/sirupsen/logrus"
)
// BGPLookup will use the Equinix Metal API functions to populate the BGP information
@@ -25,7 +26,7 @@ func BGPLookup(c *packngo.Client, k *kubevip.Config) error {
return fmt.Errorf("Unable to find local/this device in Equinix Metal API")
}
log.Infof("Querying BGP settings for [%s]", thisDevice.Hostname)
log.Info("Querying BGP settings", "hostname", thisDevice.Hostname)
neighbours, _, err := c.Devices.ListBGPNeighbors(thisDevice.ID, &packngo.ListOptions{})
if err != nil {
return err
@@ -37,7 +38,7 @@ func BGPLookup(c *packngo.Client, k *kubevip.Config) error {
// Add a warning (TODO)
if len(neighbours) > 1 {
log.Warnf("There are [%d] neighbours, only designed to manage one", len(neighbours))
log.Warn(fmt.Sprintf("There are [%d] neighbours, only designed to manage one", len(neighbours)))
}
// Ensure a peer exists

View File

@@ -4,9 +4,10 @@ import (
"fmt"
"path"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/packethost/packngo"
log "github.com/sirupsen/logrus"
)
// AttachEIP will use the Equinix Metal APIs to move an EIP and attach to a host
@@ -34,7 +35,7 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, _ string) error {
for _, ip := range ips {
// Find the device id for our EIP
if ip.Address == vip {
log.Infof("Found EIP ->%s ID -> %s\n", ip.Address, ip.ID)
log.Info("Found EIP", "address", ip.Address, "id", ip.ID)
// If attachments already exist then remove them
if len(ip.Assignments) != 0 {
hrefID := path.Base(ip.Assignments[0].Href)
@@ -53,7 +54,7 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, _ string) error {
}
// Assign the EIP to this device
log.Infof("Assigning EIP to -> %s\n", thisDevice.Hostname)
log.Info("Assigning EIP", "hostname", thisDevice.Hostname)
_, _, err := c.DeviceIPs.Assign(thisDevice.ID, &packngo.AddressStruct{
Address: vip,
})

View File

@@ -5,15 +5,16 @@ import (
"fmt"
"os"
log "log/slog"
"github.com/packethost/packngo"
log "github.com/sirupsen/logrus"
)
func findProject(project string, c *packngo.Client) *packngo.Project {
l := &packngo.ListOptions{Includes: []string{project}}
ps, _, err := c.Projects.List(l)
if err != nil {
log.Error(err)
log.Error(err.Error())
}
for _, p := range ps {

View File

@@ -5,8 +5,9 @@ import (
"hash/fnv"
"time"
log "log/slog"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/client/v3/concurrency"
@@ -147,9 +148,9 @@ watcher:
m.isLeader = true
m.key = m.election.Key() // by this time, this should already be set, since Campaign has already returned
log.Debugf("[%s] Marking self as leader with key %s\n", m.memberID, m.key)
log.Debug("Marking self as leader with key", "id", m.memberID, "key", m.key)
case response := <-changes:
log.Debugf("[%s] Leader Changes: %+v\n", m.memberID, response)
log.Debug("Leader Changes", "id", m.memberID, "response", response)
if len(response.Kvs) == 0 {
// There is a race condition where just after we stop being the leader
// if there are no more leaders, we might get a response with no key-values
@@ -181,15 +182,15 @@ watcher:
m.callbacks.OnStoppedLeading()
}
log.Debugf("[%s] Exiting watcher\n", m.memberID)
log.Debug("Exiting watcher", "id", m.memberID)
}
func (m *member) tryToBeLeader(ctx context.Context) {
if err := m.election.Campaign(ctx, m.memberID); err != nil {
log.Errorf("Failed trying to become the leader: %s", err)
log.Error("Failed trying to become the leader", "err", err)
// Resign just in case we acquired leadership just before failing
if err := m.election.Resign(m.client.Ctx()); err != nil {
log.Warnf("Failed to resign after we failed becoming the leader, this might not be a problem if we were never the leader: %s", err)
log.Warn("Failed to resign after we failed becoming the leader, this might not be a problem if we were never the leader", "err", err)
}
return
// TODO: what to do here?
@@ -209,7 +210,7 @@ func (m *member) tryToBeLeader(ctx context.Context) {
// the previous leader to detect the new leadership (if there was one) and
// stop its processes
// TODO: is this too cautious?
log.Debugf("[%s] Waiting %d seconds before running OnStartedLeading", m.memberID, m.leaseTTL)
log.Debug("timeout before OnStartedLeading", "id", m.memberID, "timeout", m.leaseTTL)
time.Sleep(time.Second * time.Duration(m.leaseTTL))
// We are the leader, execute our code
@@ -221,6 +222,6 @@ func (m *member) tryToBeLeader(ctx context.Context) {
func (m *member) resignOnCancel(ctx context.Context) {
<-ctx.Done()
if err := m.election.Resign(m.client.Ctx()); err != nil {
log.Errorf("Failed to resign after the context was canceled: %s", err)
log.Error("Failed to resign after the context was canceled", "err", err)
}
}

View File

@@ -6,7 +6,8 @@ import (
"net"
"time"
log "github.com/sirupsen/logrus"
log "log/slog"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
@@ -99,21 +100,21 @@ func FindWorkingKubernetesAddress(configPath string, inCluster bool) (*rest.Conf
return nil, err
}
for x := range ips {
log.Debugf("[k8s client] checking with IP address [%s]", ips[x].String())
log.Debug("[k8s client] testing", "address", ips[x].String())
c, err := NewRestConfig(configPath, inCluster, net.JoinHostPort(ips[x].String(), "6443"))
if err != nil {
log.Errorf("failed to create k8s REST config: %v", err)
log.Error("failed to create k8s REST config", "err", err)
}
c.Timeout = 2 * time.Second
k, err := NewClientset(c)
if err != nil {
log.Errorf("failed to create k8s clientset: %v", err)
log.Error("failed to create k8s clientset", "err", err)
}
_, err = k.DiscoveryClient.ServerVersion()
if err == nil {
log.Infof("[k8s client] working with IP address [%s]", ips[x].String())
log.Info("[k8s client] working", "address", ips[x].String())
c.Timeout = defaultTimeout
return c, nil
}

View File

@@ -3,7 +3,8 @@ package kubevip
import (
"fmt"
log "github.com/sirupsen/logrus"
log "log/slog"
"github.com/vishvananda/netlink"
)
@@ -44,8 +45,8 @@ func isValidInterface(iface string) error {
// userspace has set operational state. Interface must be considered for user
// data as setting operational state has not been implemented in every driver."
if attrs.OperState == netlink.OperUnknown {
log.Warningf(
"the status of the interface %s is unknown. Ensure your interface is ready to accept traffic, if so you can safely ignore this message",
log.Warn(
"the status of the interface is unknown. Ensure your interface is ready to accept traffic, if so you can safely ignore this message", "interface",
iface,
)
} else if attrs.OperState != netlink.OperUp {

View File

@@ -7,11 +7,12 @@ import (
"strings"
"sync"
log "log/slog"
"github.com/cloudflare/ipvs"
"github.com/cloudflare/ipvs/netmask"
"github.com/kube-vip/kube-vip/pkg/backend"
"github.com/kube-vip/kube-vip/pkg/sysctl"
log "github.com/sirupsen/logrus"
)
/*
@@ -51,28 +52,32 @@ func NewIPVSLB(address string, port uint16, forwardingMethod string, backendHeal
// Create IPVS client
c, err := ipvs.New()
if err != nil {
log.Errorf("ensure IPVS kernel modules are loaded")
log.Fatalf("Error starting IPVS [%v]", err)
log.Error("ensure IPVS kernel modules are loaded")
log.Error("Error starting IPVS", "err", err)
panic("")
}
i, err := c.Info()
if err != nil {
log.Errorf("ensure IPVS kernel modules are loaded")
log.Fatalf("Error getting IPVS version [%v]", err)
log.Error("ensure IPVS kernel modules are loaded")
log.Error("Error retrieving IPVS info", "err", err)
panic("")
}
log.Infof("IPVS Loadbalancer enabled for %d.%d.%d", i.Version[0], i.Version[1], i.Version[2])
log.Info("IPVS Loadbalancer enabled", "version", fmt.Sprintf(" %d.%d.%d", i.Version[0], i.Version[1], i.Version[2]))
if strings.ToLower(forwardingMethod) == "masquerade" {
err = sysctl.WriteProcSys("/proc/sys/net/ipv4/vs/conntrack", "1")
if err != nil {
log.Fatalf("Error ensuring net.ipv4.vs.conntrack enabled [%v]", err)
log.Error("ensuring net.ipv4.vs.conntrack enabled", "err", err)
panic("")
}
log.Infof("sysctl set net.ipv4.vs.conntrack to 1")
log.Info("sysctl set net.ipv4.vs.conntrack to 1")
err = sysctl.WriteProcSys("/proc/sys/net/ipv4/ip_forward", "1")
if err != nil {
log.Fatalf("Error ensuring net.ipv4.ip_forward enabled [%v]", err)
log.Error("ensuring net.ipv4.ip_forward enabled", "err", err)
panic("")
}
log.Infof("sysctl set net.ipv4.ip_forward to 1")
log.Info("sysctl set net.ipv4.ip_forward to 1")
}
ip, family := ipAndFamily(address)
@@ -106,7 +111,7 @@ func NewIPVSLB(address string, port uint16, forwardingMethod string, backendHeal
m = ipvs.Bypass
default:
m = ipvs.Local
log.Warnf("unknown forwarding method. Defaulting to Local")
log.Warn("unknown forwarding method. Defaulting to Local")
}
if backendHealthCheckInterval <= 0 {
@@ -161,14 +166,14 @@ func (lb *IPVSLoadBalancer) addBackend(backend backend.Entry) error {
// Check if this is the first backend
backends, err := lb.client.Destinations(lb.loadBalancerService)
if err != nil && strings.Contains(err.Error(), "file does not exist") {
log.Errorf("Error querying backends %s", err)
log.Error("querying backends", "err", err)
}
// If this is our first backend, then we can create the load-balancer service and add a backend
if len(backends) == 0 {
err = lb.client.CreateService(lb.loadBalancerService)
// If we've an error it could be that the IPVS lb instance has been left from a previous leadership
if err != nil && strings.Contains(err.Error(), "file exists") {
log.Warnf("load balancer for API server already exists, attempting to remove and re-create")
log.Warn("load balancer for API server already exists, attempting to remove and re-create")
err = lb.client.RemoveService(lb.loadBalancerService)
if err != nil {
return fmt.Errorf("error re-creating IPVS service: %v", err)
@@ -179,10 +184,12 @@ func (lb *IPVSLoadBalancer) addBackend(backend backend.Entry) error {
}
} else if err != nil {
// Fatal error at this point as IPVS is probably not working
log.Errorf("Unable to create an IPVS service, ensure IPVS kernel modules are loaded")
log.Fatalf("IPVS service error: %v", err)
log.Error("Unable to create an IPVS service, ensure IPVS kernel modules are loaded")
log.Error("IPVS service", "err", err)
panic("")
}
log.Infof("Created Load-Balancer services on [%s:%d]", lb.addrString(), lb.Port)
log.Info("load-Balancer services created", "address", lb.addrString(), "port", lb.Port)
}
ip, family := ipAndFamily(backend.Addr)
@@ -211,7 +218,7 @@ func (lb *IPVSLoadBalancer) addBackend(backend backend.Entry) error {
// file exists is fine, we will just return at this point
return nil
}
log.Infof("Added backend for [%s:%d] on [%s:%d]", lb.addrString(), lb.Port, backend.Addr, backend.Port)
log.Info("backend added", "src addr", lb.addrString(), "src port", lb.Port, "dst addr", backend.Addr, "dst port", backend.Port)
return nil
}
@@ -274,17 +281,17 @@ func (lb *IPVSLoadBalancer) healthCheck() {
if !oldStatus {
err := lb.AddBackend(backend.Addr, backend.Port)
if err != nil {
log.Errorf("failed to add backend: %s", err)
log.Error("add backend", "err", err)
}
lb.backendMap[backend] = newStatus
}
} else {
// old status -> not health
if oldStatus {
log.Infof("healthCheck failed for backend %s:%d, attempting to remove from load balancer", backend.Addr, backend.Port)
log.Info("healthCheck failed removing backend", "address", backend.Addr, "port", backend.Port)
err := lb.removeBackend(backend.Addr, backend.Port)
if err != nil {
log.Errorf("failed to remove backend %s:%d: %s", backend.Addr, backend.Port, err)
log.Error("failed to remove backend", "address", backend.Addr, "port", backend.Port, "err", err)
}
lb.backendMap[backend] = newStatus
}

View File

@@ -5,7 +5,8 @@ import (
"net"
"strconv"
log "github.com/sirupsen/logrus"
log "log/slog"
"github.com/vishvananda/netlink"
v1 "k8s.io/api/core/v1"
@@ -57,10 +58,10 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) {
if svcInterface == kubevip.Auto {
link, err = autoFindInterface(address)
if err != nil {
log.Errorf("failed to automatically discover network interface for annotated IP address [%s] with error: %s", address, err.Error())
log.Error("automatically discover network interface for annotated IP", "address", address, "err", err)
} else {
if link == nil {
log.Errorf("failed to automatically discover network interface for annotated IP address [%s]", address)
log.Error("automatically discover network interface for annotated IP address", "address", address)
}
}
if link == nil {
@@ -75,9 +76,9 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) {
case kubevip.Auto:
link, err = autoFindInterface(address)
if err != nil {
log.Errorf("failed to automatically discover network interface for IP address [%s] with error: %s - defaulting to: %s", address, err.Error(), config.Interface)
log.Error("failed to automatically discover network interface for address", "ip", address, "err", err, "interface", config.Interface)
} else if link == nil {
log.Errorf("failed to automatically discover network interface for IP address [%s] - defaulting to: %s", address, config.Interface)
log.Error("failed to automatically discover network interface for address", "ip", address, "defaulting to", config.Interface)
}
svcInterface = getAutoInterfaceName(link, config.Interface)
case "":
@@ -229,7 +230,7 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) {
for _, vipConfig := range instance.vipConfigs {
c, err := cluster.InitCluster(vipConfig, false)
if err != nil {
log.Errorf("Failed to add Service %s/%s", svc.Namespace, svc.Name)
log.Error("Failed to add Service %s/%s", svc.Namespace, svc.Name)
return nil, err
}
@@ -238,7 +239,7 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) {
}
instance.clusters = append(instance.clusters, c)
log.Infof("(svcs) adding VIP [%s] via %s for [%s/%s]", vipConfig.VIP, vipConfig.Interface, svc.Namespace, svc.Name)
log.Info("(svcs) adding VIP", "ip", vipConfig.VIP, "interface", vipConfig.Interface, "namespace", svc.Namespace, "name", svc.Name)
}
@@ -317,7 +318,7 @@ func (i *Instance) startDHCP() error {
// Check if the interface doesn't exist first
iface, err := net.InterfaceByName(interfaceName)
if err != nil {
log.Infof("Creating new macvlan interface for DHCP [%s]", interfaceName)
log.Info("creating new macvlan interface for DHCP", "interface", interfaceName)
hwaddr, err := net.ParseMAC(i.dhcpInterfaceHwaddr)
if i.dhcpInterfaceHwaddr != "" && err != nil {
@@ -329,7 +330,7 @@ func (i *Instance) startDHCP() error {
}
}
log.Infof("New interface [%s] mac is %s", interfaceName, hwaddr)
log.Info("new macvlan interface", "interface", interfaceName, "hardware address", hwaddr)
mac := &netlink.Macvlan{
LinkAttrs: netlink.LinkAttrs{
Name: interfaceName,
@@ -354,7 +355,7 @@ func (i *Instance) startDHCP() error {
return fmt.Errorf("error finding new DHCP interface by name [%v]", err)
}
} else {
log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName)
log.Info("Using existing macvlan interface for DHCP", "interface", interfaceName)
}
var initRebootFlag bool
@@ -366,7 +367,7 @@ func (i *Instance) startDHCP() error {
// Add hostname to dhcp client if annotated
if i.dhcpHostname != "" {
log.Infof("Hostname specified for dhcp lease: [%s] - [%s]", interfaceName, i.dhcpHostname)
log.Info("Hostname specified for dhcp lease", "interface", interfaceName, "hostname", i.dhcpHostname)
client.WithHostName(i.dhcpHostname)
}

View File

@@ -12,6 +12,8 @@ import (
"syscall"
"time"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/k8s"
"github.com/kube-vip/kube-vip/pkg/kubevip"
@@ -19,7 +21,6 @@ import (
"github.com/kube-vip/kube-vip/pkg/upnp"
"github.com/kube-vip/kube-vip/pkg/utils"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
@@ -72,14 +73,14 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) {
// we set it to hostname as a fallback.
// This mimics legacy behavior and should work on old kube-vip installations.
if config.NodeName == "" {
log.Warning("Node name is missing from the config, fall back to hostname")
log.Warn("Node name is missing from the config, fall back to hostname")
hostname, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf("could not get hostname: %v", err)
}
config.NodeName = hostname
}
log.Infof("Using node name [%v]", config.NodeName)
log.Info("using node name", "name", config.NodeName)
adminConfigPath := "/etc/kubernetes/admin.conf"
homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config")
@@ -93,7 +94,7 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) {
// Do nothing, we don't construct a k8s client for etcd leader election
case utils.FileExists(adminConfigPath):
if config.KubernetesAddr != "" {
log.Infof("k8s address [%s]", config.KubernetesAddr)
log.Info("k8s address", "address", config.KubernetesAddr)
clientConfig, err = k8s.NewRestConfig(adminConfigPath, false, config.KubernetesAddr)
} else if config.EnableControlPlane {
// If this is a control plane host it will likely have started as a static pod or won't have the
@@ -114,7 +115,7 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) {
if clientset, err = k8s.NewClientset(clientConfig); err != nil {
return nil, fmt.Errorf("could not create k8s clientset: %w", err)
}
log.Debugf("Using external Kubernetes configuration from file: %q", adminConfigPath)
log.Debug("Using external Kubernetes configuration from file", "path", adminConfigPath)
case utils.FileExists(homeConfigPath):
clientConfig, err = k8s.NewRestConfig(homeConfigPath, false, "")
if err != nil {
@@ -124,7 +125,7 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) {
if err != nil {
return nil, fmt.Errorf("could not create k8s clientset from external file: %q: %w", homeConfigPath, err)
}
log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath)
log.Debug("Using external Kubernetes configuration from file", "path", adminConfigPath)
default:
clientConfig, err = k8s.NewRestConfig("", true, "")
if err != nil {
@@ -210,7 +211,7 @@ func (sm *Manager) Start() error {
return err
}
log.Infoln("Starting Kube-vip Manager with the BGP engine")
log.Info("Starting Kube-vip Manager with the BGP engine")
return sm.startBGP()
}
@@ -222,13 +223,17 @@ func (sm *Manager) Start() error {
sm.upnp = true
clients := upnp.GetConnectionClients(context.TODO())
if len(clients) == 0 {
log.Errorf("Error Enabling UPNP. No Clients found")
log.Error("Error Enabling UPNP. No Clients found")
// Set the struct to false so nothing should use it in future
sm.upnp = false
} else {
for _, c := range clients {
ip, err := c.GetExternalIPAddress()
log.Infof("Found UPNP IGD2 Gateway address[%s] error: [%s]", ip, err)
if err != nil {
log.Error("unable to find IGD2 Gateway address", "err", err)
}
log.Info("Found UPNP IGD2 Gateway address", "ip", ip)
}
}
}
@@ -238,21 +243,21 @@ func (sm *Manager) Start() error {
// If ARP is enabled then we start a LeaderElection that will use ARP to advertise VIPs
if sm.config.EnableARP {
log.Infoln("Starting Kube-vip Manager with the ARP engine")
log.Info("Starting Kube-vip Manager with the ARP engine")
return sm.startARP(sm.config.NodeName)
}
if sm.config.EnableWireguard {
log.Infoln("Starting Kube-vip Manager with the Wireguard engine")
log.Info("Starting Kube-vip Manager with the Wireguard engine")
return sm.startWireguard(sm.config.NodeName)
}
if sm.config.EnableRoutingTable {
log.Infoln("Starting Kube-vip Manager with the Routing Table engine")
log.Info("Starting Kube-vip Manager with the Routing Table engine")
return sm.startTableMode(sm.config.NodeName)
}
log.Errorln("prematurely exiting Load-balancer as no modes [ARP/BGP/Wireguard] are enabled")
log.Error("prematurely exiting Load-balancer as no modes [ARP/BGP/Wireguard] are enabled")
return nil
}
@@ -268,7 +273,7 @@ func returnNameSpace() (string, error) {
func (sm *Manager) parseAnnotations() error {
if sm.config.Annotations == "" {
log.Debugf("No Node annotations to parse")
log.Debug("No Node annotations to parse")
return nil
}
@@ -290,7 +295,7 @@ func (sm *Manager) serviceInterface() string {
func (sm *Manager) startTrafficMirroringIfEnabled() error {
if sm.config.MirrorDestInterface != "" {
svcIf := sm.serviceInterface()
log.Infof("mirroring traffic from interface %s to interface %s", svcIf, sm.config.MirrorDestInterface)
log.Info("mirroring traffic", "src", svcIf, "dest", sm.config.MirrorDestInterface)
if err := trafficmirror.MirrorTrafficFromNIC(svcIf, sm.config.MirrorDestInterface); err != nil {
return err
}
@@ -303,7 +308,7 @@ func (sm *Manager) startTrafficMirroringIfEnabled() error {
func (sm *Manager) stopTrafficMirroringIfEnabled() error {
if sm.config.MirrorDestInterface != "" {
svcIf := sm.serviceInterface()
log.Infof("clean up qdisc config on interface %s", svcIf)
log.Info("clean up qdisc config", "interface", svcIf)
if err := trafficmirror.CleanupQDSICFromNIC(svcIf); err != nil {
return err
}
@@ -314,9 +319,9 @@ func (sm *Manager) stopTrafficMirroringIfEnabled() error {
}
func (sm *Manager) findServiceInstance(svc *v1.Service) *Instance {
log.Debugf("service UID: %s", svc.UID)
log.Debug("finding service", "UID", svc.UID)
for i := range sm.serviceInstances {
log.Debugf("saved service instance %d UID: %s", i, sm.serviceInstances[i].serviceSnapshot.UID)
log.Debug("saved service", "instance", i, "UID", sm.serviceInstances[i].serviceSnapshot.UID)
if sm.serviceInstances[i].serviceSnapshot.UID == svc.UID {
return sm.serviceInstances[i]
}
@@ -330,11 +335,11 @@ func (sm *Manager) refreshUPNPForwards() {
for {
time.Sleep(300 * time.Second)
log.Infof("[UPNP] Refreshing %d Instances", len(sm.serviceInstances))
log.Info("[UPNP] Refreshing Instances", "number of instances", len(sm.serviceInstances))
for i := range sm.serviceInstances {
sm.upnpMap(context.TODO(), sm.serviceInstances[i])
if err := sm.updateStatus(sm.serviceInstances[i]); err != nil {
log.Warnf("[UPNP] Error updating service IPs %s [%s]", sm.serviceInstances[i].serviceSnapshot.Name, err.Error())
log.Warn("[UPNP] Error updating service", "ip", sm.serviceInstances[i].serviceSnapshot.Name, "err", err)
}
}
}

View File

@@ -6,7 +6,8 @@ import (
"syscall"
"time"
log "github.com/sirupsen/logrus"
log "log/slog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
@@ -54,7 +55,7 @@ func (sm *Manager) startARP(id string) error {
go func() {
err := cpCluster.StartCluster(sm.config, clusterManager, nil)
if err != nil {
log.Errorf("Control Plane Error [%v]", err)
log.Error("starting control plane", "err", err)
// Trigger the shutdown of this manager instance
sm.signalChan <- syscall.SIGINT
@@ -64,7 +65,7 @@ func (sm *Manager) startARP(id string) error {
// Check if we're also starting the services, if not we can sit and wait on the closing channel and return here
if !sm.config.EnableServices {
<-sm.signalChan
log.Infof("Shutting down Kube-Vip")
log.Info("Shutting down Kube-Vip")
return nil
}
@@ -74,7 +75,7 @@ func (sm *Manager) startARP(id string) error {
ns, err = returnNameSpace()
if err != nil {
log.Warnf("unable to auto-detect namespace, dropping to [%s]", sm.config.Namespace)
log.Warn("unable to auto-detect namespace, dropping to config", "namespace", sm.config.Namespace)
ns = sm.config.Namespace
}
}
@@ -87,14 +88,14 @@ func (sm *Manager) startARP(id string) error {
// Start a services watcher (all kube-vip pods will watch services), upon a new service
// a lock based upon that service is created that they will all leaderElection on
if sm.config.EnableServicesElection {
log.Infof("beginning watching services, leaderelection will happen for every service")
log.Info("beginning watching services, leaderelection will happen for every service")
err = sm.startServicesWatchForLeaderElection(ctx)
if err != nil {
return err
}
} else {
log.Infof("beginning services leadership, namespace [%s], lock name [%s], id [%s]", ns, sm.config.ServicesLeaseName, id)
log.Info("beginning services leadership", "namespace", ns, "lock name", sm.config.ServicesLeaseName, "id", id)
// we use the Lease lock type since edits to Leases are less common
// and fewer objects in the cluster watch "all Leases".
lock := &resourcelock.LeaseLock{
@@ -125,19 +126,21 @@ func (sm *Manager) startARP(id string) error {
OnStartedLeading: func(ctx context.Context) {
err = sm.servicesWatcher(ctx, sm.syncServices)
if err != nil {
log.Fatal(err)
log.Error("service watcher", "err", err)
panic("") // TODO: - emulating log.fatal here
}
},
OnStoppedLeading: func() {
// we can do cleanup here
log.Infof("leader lost: %s", id)
log.Info("leader lost", "new leader", id)
for _, instance := range sm.serviceInstances {
for _, cluster := range instance.clusters {
cluster.Stop()
}
}
log.Fatal("lost leadership, restarting kube-vip")
log.Error("lost leadership, restarting kube-vip")
panic("") // TODO: - emulating log.fatal here
},
OnNewLeader: func(identity string) {
// we're notified when new leader elected
@@ -148,7 +151,7 @@ func (sm *Manager) startARP(id string) error {
// I just got the lock
return
}
log.Infof("new leader elected: %s", identity)
log.Info("new leader elected", "new leader", identity)
},
},
})

View File

@@ -6,13 +6,14 @@ import (
"os"
"syscall"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/bgp"
"github.com/kube-vip/kube-vip/pkg/cluster"
"github.com/kube-vip/kube-vip/pkg/equinixmetal"
api "github.com/osrg/gobgp/v3/api"
"github.com/packethost/packngo"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
)
// Start will begin the Manager, which will start services and watch the configmap
@@ -42,7 +43,7 @@ func (sm *Manager) startBGP() error {
// We're using Equinix Metal with BGP, populate the Peer information from the API
if sm.config.EnableBGP {
log.Infoln("Looking up the BGP configuration from Equinix Metal")
log.Info("Looking up the BGP configuration from Equinix Metal")
err = equinixmetal.BGPLookup(packetClient, sm.config)
if err != nil {
return err
@@ -115,7 +116,7 @@ func (sm *Manager) startBGP() error {
err = cpCluster.StartVipService(sm.config, clusterManager, sm.bgpServer, packetClient)
}
if err != nil {
log.Errorf("Control Plane Error [%v]", err)
log.Error("Control Plane", "err", err)
// Trigger the shutdown of this manager instance
sm.signalChan <- syscall.SIGINT
}
@@ -124,7 +125,7 @@ func (sm *Manager) startBGP() error {
// Check if we're also starting the services, if not we can sit and wait on the closing channel and return here
if !sm.config.EnableServices {
<-sm.signalChan
log.Infof("Shutting down Kube-Vip")
log.Info("Shutting down Kube-Vip")
return nil
}
@@ -135,7 +136,7 @@ func (sm *Manager) startBGP() error {
return err
}
log.Infof("Shutting down Kube-Vip")
log.Info("Shutting down Kube-Vip")
return nil
}

View File

@@ -8,10 +8,11 @@ import (
"syscall"
"time"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/cluster"
"github.com/kube-vip/kube-vip/pkg/iptables"
"github.com/kube-vip/kube-vip/pkg/vip"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/leaderelection"
@@ -27,14 +28,14 @@ func (sm *Manager) startTableMode(id string) error {
// want to step down
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
log.Infof("all routing table entries will exist in table [%d] with protocol [%d]", sm.config.RoutingTableID, sm.config.RoutingProtocol)
log.Info("destination for routes", "table", sm.config.RoutingTableID, "protocol", sm.config.RoutingProtocol)
if sm.config.CleanRoutingTable {
go func() {
// we assume that after 10s all services should be configured so we can delete redundant routes
time.Sleep(time.Second * 10)
if err := sm.cleanRoutes(); err != nil {
log.Errorf("error checking for old routes: %v", err)
log.Error("error checking for old routes", "err", err)
}
}()
}
@@ -43,12 +44,12 @@ func (sm *Manager) startTableMode(id string) error {
if egressCleanEnv != "" {
egressClean, err := strconv.ParseBool(egressCleanEnv)
if err != nil {
log.Warnf("failed to parse EGRESS_CLEAN env value [%s]. Egress cleaning will not be performed: %s", egressCleanEnv, err.Error())
log.Warn("failed to parse EGRESS_CLEAN env value [%s]. Egress cleaning will not be performed: %s", egressCleanEnv, err.Error())
}
if egressClean {
vip.ClearIPTables(sm.config.EgressWithNftables, sm.config.ServiceNamespace, iptables.ProtocolIPv4)
vip.ClearIPTables(sm.config.EgressWithNftables, sm.config.ServiceNamespace, iptables.ProtocolIPv6)
log.Debug("IPTables rules cleaned on startup")
log.Debug("IPtables rules cleaned on startup")
}
}
@@ -76,28 +77,28 @@ func (sm *Manager) startTableMode(id string) error {
}
if err := cpCluster.StartVipService(sm.config, clusterManager, nil, nil); err != nil {
log.Errorf("Control Plane Error [%v]", err)
log.Error("Control Plane", "err", err)
// Trigger the shutdown of this manager instance
sm.signalChan <- syscall.SIGINT
}
} else {
ns, err := returnNameSpace()
if err != nil {
log.Warnf("unable to auto-detect namespace, dropping to [%s]", sm.config.Namespace)
log.Warn("unable to auto-detect namespace", "dropping to", sm.config.Namespace)
ns = sm.config.Namespace
}
// Start a services watcher (all kube-vip pods will watch services), upon a new service
// a lock based upon that service is created that they will all leaderElection on
if sm.config.EnableServicesElection {
log.Infof("beginning watching services, leaderelection will happen for every service")
log.Info("beginning watching services, leaderelection will happen for every service")
err = sm.startServicesWatchForLeaderElection(ctx)
if err != nil {
return err
}
} else if sm.config.EnableLeaderElection {
log.Infof("beginning services leadership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, id)
log.Info("beginning services leadership", "namespace", ns, "lock name", plunderLock, "id", id)
// we use the Lease lock type since edits to Leases are less common
// and fewer objects in the cluster watch "all Leases".
lock := &resourcelock.LeaseLock{
@@ -127,19 +128,21 @@ func (sm *Manager) startTableMode(id string) error {
OnStartedLeading: func(ctx context.Context) {
err = sm.servicesWatcher(ctx, sm.syncServices)
if err != nil {
log.Fatal(err)
log.Error(err.Error())
panic("")
}
},
OnStoppedLeading: func() {
// we can do cleanup here
log.Infof("leader lost: %s", id)
log.Info("leader lost", "id", id)
for _, instance := range sm.serviceInstances {
for _, cluster := range instance.clusters {
cluster.Stop()
}
}
log.Fatal("lost leadership, restarting kube-vip")
log.Error("lost leadership, restarting kube-vip")
panic("")
},
OnNewLeader: func(identity string) {
// we're notified when new leader elected
@@ -147,15 +150,15 @@ func (sm *Manager) startTableMode(id string) error {
// I just got the lock
return
}
log.Infof("new leader elected: %s", identity)
log.Info("new leader elected", "id", identity)
},
},
})
} else {
log.Infof("beginning watching services without leader election")
log.Info("beginning watching services without leader election")
err = sm.servicesWatcher(ctx, sm.syncServices)
if err != nil {
log.Errorf("Cannot watch services, %v", err)
log.Error("Cannot watch services", "err", err)
}
}
}
@@ -189,9 +192,9 @@ func (sm *Manager) cleanRoutes() error {
if !found {
err = netlink.RouteDel(&(routes[i]))
if err != nil {
log.Errorf("[route] error deleting route: %v", routes[i])
log.Error("[route] deletion", "route", routes[i], "err", err)
}
log.Debugf("[route] deleted route: %v", routes[i])
log.Debug("[route] deletion", "route", routes[i])
}
}

View File

@@ -4,8 +4,9 @@ import (
"context"
"time"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/wireguard"
log "github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
@@ -20,7 +21,7 @@ func (sm *Manager) startWireguard(id string) error {
// want to step down
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
log.Infoln("reading wireguard peer configuration from Kubernetes secret")
log.Info("reading wireguard peer configuration from Kubernetes secret")
s, err := sm.clientSet.CoreV1().Secrets(sm.config.Namespace).Get(ctx, "wireguard", metav1.GetOptions{})
if err != nil {
return err
@@ -47,21 +48,21 @@ func (sm *Manager) startWireguard(id string) error {
ns, err = returnNameSpace()
if err != nil {
log.Warnf("unable to auto-detect namespace, dropping to [%s]", sm.config.Namespace)
log.Warn("unable to auto-detect namespace", "dropping to", sm.config.Namespace)
ns = sm.config.Namespace
}
// Start a services watcher (all kube-vip pods will watch services), upon a new service
// a lock based upon that service is created that they will all leaderElection on
if sm.config.EnableServicesElection {
log.Infof("beginning watching services, leaderelection will happen for every service")
log.Info("beginning watching services, leaderelection will happen for every service")
err = sm.startServicesWatchForLeaderElection(ctx)
if err != nil {
return err
}
} else {
log.Infof("beginning services leadership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, id)
log.Info("beginning services leadership", "namespace", ns, "lock name", plunderLock, "id", id)
// we use the Lease lock type since edits to Leases are less common
// and fewer objects in the cluster watch "all Leases".
lock := &resourcelock.LeaseLock{
@@ -92,19 +93,21 @@ func (sm *Manager) startWireguard(id string) error {
OnStartedLeading: func(ctx context.Context) {
err = sm.servicesWatcher(ctx, sm.syncServices)
if err != nil {
log.Fatal(err)
log.Error(err.Error())
panic("")
}
},
OnStoppedLeading: func() {
// we can do cleanup here
log.Infof("leader lost: %s", id)
log.Info("leader lost", "id", id)
for _, instance := range sm.serviceInstances {
for _, cluster := range instance.clusters {
cluster.Stop()
}
}
log.Fatal("lost leadership, restarting kube-vip")
log.Error("lost leadership, restarting kube-vip")
panic("")
},
OnNewLeader: func(identity string) {
// we're notified when new leader elected
@@ -112,7 +115,7 @@ func (sm *Manager) startWireguard(id string) error {
// I just got the lock
return
}
log.Infof("new leader elected: %s", identity)
log.Info("new leader elected", "id", identity)
},
},
})

View File

@@ -5,7 +5,8 @@ import (
"encoding/json"
"fmt"
log "github.com/sirupsen/logrus"
log "log/slog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
@@ -28,21 +29,21 @@ func applyNodeLabel(clientSet *kubernetes.Clientset, address, id, identity strin
ctx := context.Background()
node, err := clientSet.CoreV1().Nodes().Get(ctx, id, metav1.GetOptions{})
if err != nil {
log.Errorf("can't query node %s labels. error: %v", id, err)
log.Error("can't query node labels", "node", id, "err", err)
return
}
log.Debugf("node %s labels: %+v", id, node.Labels)
log.Debug(fmt.Sprintf("node %s labels: %+v", id, node.Labels))
value, ok := node.Labels[nodeLabelIndex]
path := fmt.Sprintf("/metadata/labels/%s", nodeLabelJSONPath)
log.Debugf("Received identity: %s - id: %s", identity, id)
log.Debug(fmt.Sprintf("Received identity: %s - id: %s", identity, id))
if ok && value == address {
log.Debugf("removing node label `has-ip=%s` on %s", address, id)
log.Debug(fmt.Sprintf("removing node label `has-ip=%s` on %s", address, id))
// Remove label
applyPatchLabels(ctx, clientSet, id, "remove", path, address)
} else {
log.Debugf("setting node label `has-ip=%s` on %s", address, id)
log.Debug(fmt.Sprintf("setting node label `has-ip=%s` on %s", address, id))
// Append label
applyPatchLabels(ctx, clientSet, id, "add", path, address)
}
@@ -58,15 +59,15 @@ func applyPatchLabels(ctx context.Context, clientSet *kubernetes.Clientset,
}}
patchData, err := json.Marshal(patchLabels)
if err != nil {
log.Errorf("node patch marshaling failed. error: %v", err)
log.Error("node patch marshaling failed", "err", err)
return
}
// patch node
node, err := clientSet.CoreV1().Nodes().Patch(ctx,
name, types.JSONPatchType, patchData, metav1.PatchOptions{})
if err != nil {
log.Errorf("can't patch node %s. error: %v", name, err)
log.Error("node patch marshaling failed", "err", err)
return
}
log.Debugf("updated node %s labels: %+v", name, node.Labels)
log.Debug("updated", "node", name, "labels", node.Labels)
}

View File

@@ -8,9 +8,10 @@ import (
"os"
"strings"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/iptables"
"github.com/kube-vip/kube-vip/pkg/vip"
log "github.com/sirupsen/logrus"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -58,7 +59,7 @@ func getSameFamilyCidr(sourceCidrs, ip string) string { //Todo: not sure how thi
matchingFamily = append(matchingFamily, cidr)
selectedCIDR, err := checkCIDR(ip, cidr)
if err != nil {
log.Warnf("IPv6 CIDR check failed: %s", err.Error())
log.Warn("IPv6 CIDR check ", "err", err)
continue
}
if selectedCIDR != "" {
@@ -70,7 +71,7 @@ func getSameFamilyCidr(sourceCidrs, ip string) string { //Todo: not sure how thi
matchingFamily = append(matchingFamily, cidr)
selectedCidr, err := checkCIDR(ip, cidr)
if err != nil {
log.Warnf("IPv4 CIDR check failed: %s", err.Error())
log.Warn("IPv4 CIDR check ", "err", err)
continue
}
if selectedCidr != "" {
@@ -121,7 +122,7 @@ func (sm *Manager) configureEgress(vipIP, podIP, namespace string, annotations m
}
if discoverErr != nil {
log.Warn(discoverErr)
log.Warn("autodiscover CIDR", "err", discoverErr)
}
if sm.config.EgressPodCidr != "" {
@@ -156,21 +157,21 @@ func (sm *Manager) configureEgress(vipIP, podIP, namespace string, annotations m
serviceCidr = defaultServiceCIDR
}
log.Infof("[Egress] pod CIDR [%s], service CIDR [%s] for vip [%s] / pod [%s]", podCidr, serviceCidr, vipIP, podIP)
log.Info("[Egress]", "pod CIDR", podCidr, " service CIDR", serviceCidr, "vip", serviceCidr, "pod", podIP)
// checking if all addresses are of the same IP family
if vip.IsIPv4(podIP) != vip.IsIPv4CIDR(podCidr) {
log.Errorf("[Egress] pod's IP [%s] and Pod CIDR [%s] family is not matching. Backing off...", podIP, podCidr)
log.Error("[Egress] family is not matching. Backing off...", "pod", podIP, "podCIDR", podCidr)
return nil
}
if vip.IsIPv4(vipIP) != vip.IsIPv4CIDR(serviceCidr) {
log.Errorf("[Egress] VIP's IP [%s] and Service CIDR [%s] family is not matching. Backing off...", podIP, podCidr)
log.Error("[Egress] family is not matching. Backing off...", "pod", podIP, "serviceCIDR", serviceCidr)
return nil
}
if vip.IsIPv4(vipIP) != vip.IsIPv4(podIP) {
log.Errorf("[Egress] VIP's IP [%s] and Pod's IP [%s] family is not matching. Backing off...", podIP, podCidr)
log.Error("[Egress] family is not matching. Backing off...", "pod", podIP, "vipIP", vipIP)
return nil
}
@@ -279,7 +280,7 @@ func (sm *Manager) configureEgress(vipIP, podIP, namespace string, annotations m
}
func (sm *Manager) AutoDiscoverCIDRs() (serviceCIDR, podCIDR string, err error) {
log.Debugf("Trying to automatically discover Service and Pod CIDRs")
log.Debug("Trying to automatically discover Service and Pod CIDRs")
options := v1.ListOptions{
LabelSelector: "component=kube-controller-manager",
}

View File

@@ -8,8 +8,9 @@ import (
"sync"
"time"
log "log/slog"
"github.com/google/go-cmp/cmp"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -23,7 +24,7 @@ import (
func (sm *Manager) syncServices(ctx context.Context, svc *v1.Service, wg *sync.WaitGroup) error {
defer wg.Done()
log.Debugf("[STARTING] Service Sync")
log.Debug("[STARTING] Service Sync")
// Iterate through the synchronising services
foundInstance := false
@@ -43,7 +44,7 @@ func (sm *Manager) syncServices(ctx context.Context, svc *v1.Service, wg *sync.W
break
}
for _, newServiceAddress := range newServiceAddresses {
log.Debugf("isDHCP: %t, newServiceAddress: %s", sm.serviceInstances[x].isDHCP, newServiceAddress)
log.Debug("service", "isDHCP", sm.serviceInstances[x].isDHCP, "newServiceAddress", newServiceAddress)
if sm.serviceInstances[x].serviceSnapshot.UID == newServiceUID {
// If the found instance's DHCP configuration doesn't match the new service, delete it.
if (sm.serviceInstances[x].isDHCP && newServiceAddress != "0.0.0.0") ||
@@ -102,23 +103,23 @@ func (sm *Manager) addService(ctx context.Context, svc *v1.Service) error {
if newService.isDHCP && len(newService.vipConfigs) == 1 {
go func() {
for ip := range newService.dhcpClient.IPChannel() {
log.Debugf("IP %s may have changed", ip)
log.Debug("IP changed", "ip", ip)
newService.vipConfigs[0].VIP = ip
newService.dhcpInterfaceIP = ip
if !sm.config.DisableServiceUpdates {
if err := sm.updateStatus(newService); err != nil {
log.Warnf("error updating svc: %s", err)
log.Warn("updating svc", "err", err)
}
}
}
log.Debugf("IP update channel closed, stopping")
log.Debug("IP update channel closed, stopping")
}()
}
sm.serviceInstances = append(sm.serviceInstances, newService)
if !sm.config.DisableServiceUpdates {
log.Debugf("(svcs) will update [%s/%s]", newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name)
log.Debug("service update", "namespace", newService.serviceSnapshot.Namespace, "name", newService.serviceSnapshot.Name)
if err := sm.updateStatus(newService); err != nil {
// delete service to collect garbage
if deleteErr := sm.deleteService(newService.serviceSnapshot.UID); deleteErr != nil {
@@ -132,26 +133,26 @@ func (sm *Manager) addService(ctx context.Context, svc *v1.Service) error {
// Check if we need to flush any conntrack connections (due to some dangling conntrack connections)
if svc.Annotations[flushContrack] == "true" {
log.Debugf("Flushing conntrack rules for service [%s]", svc.Name)
log.Debug("Flushing conntrack rules", "service", svc.Name)
for _, serviceIP := range serviceIPs {
err = vip.DeleteExistingSessions(serviceIP, false, svc.Annotations[egressDestinationPorts], svc.Annotations[egressSourcePorts])
if err != nil {
log.Errorf("Error flushing any remaining egress connections [%s]", err)
log.Error("flushing any remaining egress connections", "err", err)
}
err = vip.DeleteExistingSessions(serviceIP, true, svc.Annotations[egressDestinationPorts], svc.Annotations[egressSourcePorts])
if err != nil {
log.Errorf("Error flushing any remaining ingress connections [%s]", err)
log.Error("flushing any remaining ingress connections", "err", err)
}
}
}
// Check if egress is enabled on the service, if so we'll need to configure some rules
if svc.Annotations[egress] == "true" && len(serviceIPs) > 0 {
log.Debugf("Enabling egress for the service [%s]", svc.Name)
log.Debug("enabling egress", "service", svc.Name)
// We will need to modify the iptables rules
err = sm.iptablesCheck()
if err != nil {
log.Errorf("Error configuring egress for loadbalancer [%s]", err)
log.Error("configuring egress", "service", svc.Name, "err", err)
}
var podIP string
errList := []error{}
@@ -168,7 +169,7 @@ func (sm *Manager) addService(ctx context.Context, svc *v1.Service) error {
err = sm.configureEgress(serviceIP, podIP, svc.Namespace, svc.Annotations)
if err != nil {
errList = append(errList, err)
log.Errorf("Error configuring egress for loadbalancer [%s]", err)
log.Error("configuring egress", "service", svc.Name, "err", err)
}
}
}
@@ -182,7 +183,7 @@ func (sm *Manager) addService(ctx context.Context, svc *v1.Service) error {
err = sm.configureEgress(serviceIP, podIPs, svc.Namespace, svc.Annotations)
if err != nil {
errList = append(errList, err)
log.Errorf("Error configuring egress for loadbalancer [%s]", err)
log.Error("configuring egress", "service", svc.Name, "err", err)
}
}
}
@@ -195,13 +196,13 @@ func (sm *Manager) addService(ctx context.Context, svc *v1.Service) error {
}
err = provider.updateServiceAnnotation(svc.Annotations[activeEndpoint], svc.Annotations[activeEndpointIPv6], svc, sm)
if err != nil {
log.Errorf("error configuring egress annotation for loadbalancer [%s]", err)
log.Error("configuring egress", "service", svc.Name, "err", err)
}
}
}
finishTime := time.Since(startTime)
log.Infof("[service] synchronised in %dms", finishTime.Milliseconds())
log.Info("[service] synchronised", "in", fmt.Sprintf("%dms", finishTime.Milliseconds()))
return nil
}
@@ -215,7 +216,7 @@ func (sm *Manager) deleteService(uid types.UID) error {
var serviceInstance *Instance
found := false
for x := range sm.serviceInstances {
log.Debugf("Looking for [%s], found [%s]", uid, sm.serviceInstances[x].serviceSnapshot.UID)
log.Debug("service lookup", "target UID", uid, "found UID ", sm.serviceInstances[x].serviceSnapshot.UID)
// Add the running services to the new array
if sm.serviceInstances[x].serviceSnapshot.UID != uid {
updatedInstances = append(updatedInstances, sm.serviceInstances[x])
@@ -269,17 +270,17 @@ func (sm *Manager) deleteService(uid types.UID) error {
if err != nil {
return fmt.Errorf("[BGP] error deleting BGP host: %v", err)
}
log.Debugf("[BGP] deleted host: %s", cidrVip)
log.Debug("[BGP] delete", "host", cidrVip)
}
}
// We will need to tear down the egress
if serviceInstance.serviceSnapshot.Annotations[egress] == "true" {
if serviceInstance.serviceSnapshot.Annotations[activeEndpoint] != "" {
log.Infof("service [%s] has an egress re-write enabled", serviceInstance.serviceSnapshot.Name)
log.Info("egress re-write enabled", "service", serviceInstance.serviceSnapshot.Name)
err := sm.TeardownEgress(serviceInstance.serviceSnapshot.Annotations[activeEndpoint], serviceInstance.serviceSnapshot.Spec.LoadBalancerIP, serviceInstance.serviceSnapshot.Namespace, serviceInstance.serviceSnapshot.Annotations)
if err != nil {
log.Errorf("%v", err)
log.Error("egress teardown", "err", err)
}
}
}
@@ -288,7 +289,7 @@ func (sm *Manager) deleteService(uid types.UID) error {
// Update the service array
sm.serviceInstances = updatedInstances
log.Infof("Removed [%s] from manager, [%d] advertised services remain", uid, len(sm.serviceInstances))
log.Info("Removed instance from manager", "uid", uid, "remaining advertised services", len(sm.serviceInstances))
return nil
}
@@ -301,7 +302,7 @@ func (sm *Manager) upnpMap(ctx context.Context, s *Instance) {
return
}
if !sm.upnp {
log.Warnf("[UPNP] Found kube-vip.io/forwardUPNP on service while UPNP forwarding is disabled in the kube-vip config. Not forwarding service %s", s.serviceSnapshot.Name)
log.Warn("[UPNP] Found kube-vip.io/forwardUPNP on service while UPNP forwarding is disabled in the kube-vip config. Not forwarding", "service", s.serviceSnapshot.Name)
}
// If upnp is enabled then update the gateway/router with the address
// TODO - check if this implementation for dualstack is correct
@@ -314,28 +315,28 @@ func (sm *Manager) upnpMap(ctx context.Context, s *Instance) {
for _, vip := range fetchServiceAddresses(s.serviceSnapshot) {
for _, port := range s.serviceSnapshot.Spec.Ports {
for _, gw := range gateways {
log.Infof("[UPNP] Adding map to [%s:%d - %s] on gateway %s", vip, port.Port, s.serviceSnapshot.Name, gw.WANIPv6FirewallControlClient.Location)
log.Info("[UPNP] Adding map", "vip", vip, "port", port.Port, "service", s.serviceSnapshot.Name, "gateway", gw.WANIPv6FirewallControlClient.Location)
forwardSucessful := false
if gw.WANIPv6FirewallControlClient != nil {
pinholeID, pinholeErr := gw.WANIPv6FirewallControlClient.AddPinholeCtx(ctx, "0.0.0.0", uint16(port.Port), vip, uint16(port.Port), upnp.MapProtocolToIANA(string(port.Protocol)), 3600) //nolint TODO
if pinholeErr == nil {
forwardSucessful = true
log.Infof("[UPNP] Service should be accessible externally on port [%d]; PinholeID is [%d]", port.Port, pinholeID)
log.Info("[UPNP] Service should be accessible externally", "port", port.Port, "pinhold ID", pinholeID)
} else {
//TODO: Cleanup
log.Errorf("[UPNP] Unable to map port to gateway using Pinhole API[%s]", pinholeErr.Error())
log.Error("[UPNP] Unable to map port to gateway using Pinhole API", "err", pinholeErr.Error())
}
}
// Fallback to PortForward
if !forwardSucessful {
portMappingErr := gw.ConnectionClient.AddPortMapping("0.0.0.0", uint16(port.Port), strings.ToUpper(string(port.Protocol)), uint16(port.Port), vip, true, s.serviceSnapshot.Name, 3600) //nolint TODO
if portMappingErr == nil {
log.Infof("[UPNP] Service should be accessible externally on port [%d]", port.Port)
log.Info("[UPNP] Service should be accessible externally", "port", port.Port)
forwardSucessful = true
} else {
//TODO: Cleanup
log.Errorf("[UPNP] Unable to map port to gateway using PortForward API[%s]", portMappingErr.Error())
log.Error("[UPNP] Unable to map port to gateway using PortForward API", "err", portMappingErr.Error())
}
}
@@ -379,14 +380,14 @@ func (sm *Manager) updateStatus(i *Instance) error {
}
if currentService.Annotations["development.kube-vip.io/synthetic-api-server-error-on-update"] == "true" {
log.Errorf("(Synthetic error thrown) Error updating Service Spec [%s] : %v", i.serviceSnapshot.Name, err)
log.Error("(Synthetic error ) updating Spec", "service", i.serviceSnapshot.Name, "err", err)
return fmt.Errorf("(Synthetic) simulating api server errors")
}
if !cmp.Equal(currentService, currentServiceCopy) {
currentService, err = sm.clientSet.CoreV1().Services(currentServiceCopy.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{})
if err != nil {
log.Errorf("Error updating Service Spec [%s] : %v", i.serviceSnapshot.Name, err)
log.Error("updating Spec", "service", i.serviceSnapshot.Name, "err", err)
return err
}
}
@@ -435,7 +436,7 @@ func (sm *Manager) updateStatus(i *Instance) error {
currentService.Status.LoadBalancer.Ingress = ingresses
_, err = sm.clientSet.CoreV1().Services(currentService.Namespace).UpdateStatus(context.TODO(), currentService, metav1.UpdateOptions{})
if err != nil {
log.Errorf("Error updating Service %s/%s Status: %v", i.serviceSnapshot.Namespace, i.serviceSnapshot.Name, err)
log.Error("updating Service", "namespace", i.serviceSnapshot.Namespace, "name", i.serviceSnapshot.Name, "err", err)
return err
}
}
@@ -443,7 +444,7 @@ func (sm *Manager) updateStatus(i *Instance) error {
})
if retryErr != nil {
log.Errorf("Failed to set Services: %v", retryErr)
log.Error("Failed to set Services", "err", retryErr)
return retryErr
}
return nil

View File

@@ -6,7 +6,8 @@ import (
"sync"
"time"
log "github.com/sirupsen/logrus"
log "log/slog"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/leaderelection"
@@ -29,7 +30,7 @@ func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) erro
}
}
log.Infof("Shutting down kube-Vip")
log.Info("Shutting down kube-Vip")
return nil
}
@@ -37,7 +38,7 @@ func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) erro
// The startServicesWatchForLeaderElection function will start a services watcher, the
func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1.Service, wg *sync.WaitGroup) error {
serviceLease := fmt.Sprintf("kubevip-%s", service.Name)
log.Infof("(svc election) service [%s], namespace [%s], lock name [%s], host id [%s]", service.Name, service.Namespace, serviceLease, sm.config.NodeName)
log.Info("new leader election", "service", service.Name, "namespace", service.Namespace, "lock name", serviceLease, "host id", sm.config.NodeName)
// we use the Lease lock type since edits to Leases are less common
// and fewer objects in the cluster watch "all Leases".
lock := &resourcelock.LeaseLock{
@@ -73,16 +74,16 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1.
// we run this in background as it's blocking
wg.Add(1)
if err := sm.syncServices(ctx, service, wg); err != nil {
log.Error(err)
log.Error("service sync", "err", err)
childCancel()
}
},
OnStoppedLeading: func() {
// we can do cleanup here
log.Infof("(svc election) service [%s] leader lost: [%s]", service.Name, sm.config.NodeName)
log.Info("leadership lost", "service", service.Name, "leader", sm.config.NodeName)
if activeService[string(service.UID)] {
if err := sm.deleteService(service.UID); err != nil {
log.Error(err)
log.Error("service deletion", "err", err)
}
}
// Mark this service is inactive
@@ -94,10 +95,10 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1.
// I just got the lock
return
}
log.Infof("(svc election) new leader elected: %s", identity)
log.Info("new leader", "leader", identity)
},
},
})
log.Infof("(svc election) for service [%s] stopping", service.Name)
log.Info("stopping leader election", "service", service.Name)
return nil
}

View File

@@ -8,8 +8,9 @@ import (
"strconv"
"strings"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/bgp"
log "github.com/sirupsen/logrus"
"github.com/davecgh/go-spew/spew"
v1 "k8s.io/api/core/v1"
@@ -26,7 +27,7 @@ import (
// present
func (sm *Manager) annotationsWatcher() error {
// Use a restartable watcher, as this should help in the event of etcd or timeout issues
log.Infof("Kube-Vip is waiting for annotation prefix [%s] to be present on this node", sm.config.Annotations)
log.Info("Kube-Vip is waiting for annotation prefix to be present on this node", "prefix", sm.config.Annotations)
labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{"kubernetes.io/hostname": sm.config.NodeName}}
listOptions := metav1.ListOptions{
@@ -54,7 +55,7 @@ func (sm *Manager) annotationsWatcher() error {
// We got an error with the annotations, falling back to the watch until
// they're as needed
log.Warn(err)
log.Warn(err.Error())
rw, err := watchtools.NewRetryWatcher(node.ResourceVersion, &cache.ListWatch{
WatchFunc: func(_ metav1.ListOptions) (watch.Interface, error) {
@@ -94,7 +95,7 @@ func (sm *Manager) annotationsWatcher() error {
bgpConfig, bgpPeer, err := parseBgpAnnotations(sm.config.BGPConfig, node, sm.config.Annotations)
if err != nil {
log.Error(err)
log.Error(err.Error())
continue
}
@@ -108,7 +109,7 @@ func (sm *Manager) annotationsWatcher() error {
return fmt.Errorf("unable to parse Kubernetes Node from Kubernetes watcher")
}
log.Infof("Node [%s] has been deleted", node.Name)
log.Info("Node has been deleted", "name", node.Name)
case watch.Bookmark:
// Un-used
@@ -124,12 +125,12 @@ func (sm *Manager) annotationsWatcher() error {
}
status := statusErr.ErrStatus
log.Errorf("%v", status)
log.Error(status.String())
default:
}
}
close(exitFunction)
log.Infoln("Exiting Annotations watcher")
log.Info("Exiting Annotations watcher")
return nil
}

View File

@@ -9,8 +9,9 @@ import (
"sync"
"syscall"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
discoveryv1 "k8s.io/api/discovery/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -85,17 +86,17 @@ func (ep *endpointsProvider) getLocalEndpoints(id string, _ *kubevip.Config) ([]
for _, subset := range ep.endpoints.Subsets {
for _, address := range subset.Addresses {
log.Debugf("[%s] processing endpoint [%s]", ep.label, address.IP)
log.Debug("processing endpoint", "label", ep.label, "ip", address.IP)
// 1. Compare the Nodename
if address.NodeName != nil && id == *address.NodeName {
log.Debugf("[%s] found local endpoint - address: %s, hostname: %s, node: %s", ep.label, address.IP, address.Hostname, *address.NodeName)
log.Debug("found local endpoint", "label", ep.label, "ip", address.IP, "hostname", address.Hostname, "nodename", *address.NodeName)
localEndpoints = append(localEndpoints, address.IP)
continue
}
// 2. Compare the Hostname (only useful if address.NodeName is not available)
if id == address.Hostname {
log.Debugf("[%s] found local endpoint - address: %s, hostname: %s", ep.label, address.IP, address.Hostname)
log.Debug("found local endpoint", "label", ep.label, "ip", address.IP, "hostname", address.Hostname)
localEndpoints = append(localEndpoints, address.IP)
continue
}
@@ -122,14 +123,14 @@ func (ep *endpointsProvider) updateServiceAnnotation(endpoint string, _ string,
_, err = sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{})
if err != nil {
log.Errorf("[%s] error updating Service Spec [%s] : %v", ep.getLabel(), currentServiceCopy.Name, err)
log.Error("error updating Service Spec", "label", ep.getLabel(), "name", currentServiceCopy.Name, "err", err)
return err
}
return nil
})
if retryErr != nil {
log.Errorf("[%s] failed to set Services: %v", ep.getLabel(), retryErr)
log.Error("failed to set Services", "label", ep.getLabel(), "err", retryErr)
return retryErr
}
return nil
@@ -144,7 +145,7 @@ func (ep *endpointsProvider) getProtocol() string {
}
func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Service, wg *sync.WaitGroup, provider epProvider) error {
log.Infof("[%s] watching for service [%s] in namespace [%s]", provider.getLabel(), service.Name, service.Namespace)
log.Info("watching", "provide", provider.getLabel(), "service name", service.Name, "namespace", service.Namespace)
// Use a restartable watcher, as this should help in the event of etcd or timeout issues
leaderContext, cancel := context.WithCancel(ctx)
defer cancel()
@@ -161,21 +162,21 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser
go func() {
select {
case <-ctx.Done():
log.Debugf("[%s] context cancelled", provider.getLabel())
log.Debug("context cancelled", "provider", provider.getLabel())
// Stop the retry watcher
rw.Stop()
// Cancel the context, which will in turn cancel the leadership
cancel()
return
case <-sm.shutdownChan:
log.Debugf("[%s] shutdown called", provider.getLabel())
log.Debug("shutdown called", "provider", provider.getLabel())
// Stop the retry watcher
rw.Stop()
// Cancel the context, which will in turn cancel the leadership
cancel()
return
case <-exitFunction:
log.Debugf("[%s] function ending", provider.getLabel())
log.Debug("function ending", "provider", provider.getLabel())
// Stop the retry watcher
rw.Stop()
// Cancel the context, which will in turn cancel the leadership
@@ -244,11 +245,11 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser
if sm.config.EnableRoutingTable {
if err := sm.TeardownEgress(lastKnownGoodEndpoint, service.Spec.LoadBalancerIP,
service.Namespace, service.Annotations); err != nil {
log.Warnf("error removing redundant egress rules: %s", err.Error())
log.Warn("removing redundant egress rules", "err", err)
}
}
if leaderElectionActive && (sm.config.EnableServicesElection || sm.config.EnableLeaderElection) {
log.Warnf("[%s] existing [%s] has been removed, restarting leaderElection", provider.getLabel(), lastKnownGoodEndpoint)
log.Warn(" existing endpoint has been removed, restarting leaderElection", "provider", provider.getLabel(), "endpoint", lastKnownGoodEndpoint)
// Stop the existing leaderElection
cancel()
// disable last leaderElection flag
@@ -272,7 +273,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser
leaderElectionActive = true
err := sm.StartServicesLeaderElection(leaderContext, service, wg)
if err != nil {
log.Error(err)
log.Error(err.Error())
}
leaderElectionActive = false
} else {
@@ -303,15 +304,15 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser
return fmt.Errorf("[%s] error updating existing routes: %w", provider.getLabel(), err)
}
if isUpdated {
log.Debugf("[%s] updated route: %s", provider.getLabel(), cluster.Network[i].IP())
log.Debug("updated route", "provider", provider.getLabel(), "ip", cluster.Network[i].IP())
}
} else {
// If other error occurs, return error
return fmt.Errorf("[%s] error adding route: %s", provider.getLabel(), err.Error())
}
} else {
log.Infof("[%s] added route: %s, service: %s/%s, interface: %s, table: %d",
provider.getLabel(), cluster.Network[i].IP(), service.Namespace, service.Name, cluster.Network[i].Interface(), sm.config.RoutingTableID)
log.Info("added route", "provider",
provider.getLabel(), "ip", cluster.Network[i].IP(), "service name", service.Name, "namespace", service.Namespace, "interface", cluster.Network[i].Interface(), "tableID", sm.config.RoutingTableID)
configuredLocalRoutes.Store(string(service.UID), true)
leaderElectionActive = true
}
@@ -326,13 +327,13 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser
for _, cluster := range instance.clusters {
for i := range cluster.Network {
address := fmt.Sprintf("%s/%s", cluster.Network[i].IP(), sm.config.VIPCIDR)
log.Debugf("[%s] attempting to advertise BGP service: %s", provider.getLabel(), address)
log.Debug("attempting to advertise BGP service", "provider", provider.getLabel(), "ip", address)
err := sm.bgpServer.AddHost(address)
if err != nil {
log.Errorf("[%s] error adding BGP host %s\n", err.Error(), provider.getLabel())
log.Error("error adding BGP hos", "provider", provider.getLabel(), "err", err)
} else {
log.Infof("[%s] added BGP host: %s, service: %s/%s",
provider.getLabel(), address, service.Namespace, service.Name)
log.Info("added BGP host", "provider",
provider.getLabel(), "ip", address, "service name", service.Name, "namespace", service.Namespace)
configuredLocalRoutes.Store(string(service.UID), true)
leaderElectionActive = true
}
@@ -359,10 +360,10 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser
address := fmt.Sprintf("%s/%s", cluster.Network[i].IP(), sm.config.VIPCIDR)
err := sm.bgpServer.DelHost(address)
if err != nil {
log.Errorf("[%s] error deleting BGP host%s: %s\n", provider.getLabel(), address, err.Error())
log.Error("deleting BGP host", "provider", provider.getLabel(), "ip", address, "err", err)
} else {
log.Infof("[%s] deleted BGP host: %s, service: %s/%s",
provider.getLabel(), address, service.Namespace, service.Name)
log.Info("deleted BGP host", "provider",
provider.getLabel(), "ip", address, "service name", service.Name, "namespace", service.Namespace)
configuredLocalRoutes.Store(string(service.UID), false)
leaderElectionActive = false
}
@@ -374,9 +375,9 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser
// If there are no local endpoints, and we had one then remove it and stop the leaderElection
if lastKnownGoodEndpoint != "" {
log.Warnf("[%s] existing [%s] has been removed, no remaining endpoints for leaderElection", provider.getLabel(), lastKnownGoodEndpoint)
log.Warn("existing endpoint has been removed, no remaining endpoints for leaderElection", "provider", provider.getLabel(), "endpoint", lastKnownGoodEndpoint)
if err := sm.TeardownEgress(lastKnownGoodEndpoint, service.Spec.LoadBalancerIP, service.Namespace, service.Annotations); err != nil {
log.Errorf("error removing redundant egress rules: %s", err.Error())
log.Error("error removing redundant egress rules", "err", err)
}
lastKnownGoodEndpoint = "" // reset endpoint
@@ -391,8 +392,8 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser
service.Annotations[activeEndpointAnnotation] = lastKnownGoodEndpoint
}
log.Debugf("[%s watcher] service %s/%s: local endpoint(s) [%d], known good [%s], active election [%t]",
provider.getLabel(), service.Namespace, service.Name, len(endpoints), lastKnownGoodEndpoint, leaderElectionActive)
log.Debug("watcher", "provider",
provider.getLabel(), "service name", service.Name, "namespace", service.Namespace, "endpoints", len(endpoints), "last endpoint", lastKnownGoodEndpoint, "active leader election", leaderElectionActive)
case watch.Deleted:
// When no-leader-elecition mode
@@ -426,17 +427,17 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser
// Close the goroutine that will end the retry watcher, then exit the endpoint watcher function
close(exitFunction)
log.Infof("[%s] deleted stopping watching for [%s] in namespace [%s]", provider.getLabel(), service.Name, service.Namespace)
log.Info("stopping watching", "provider", provider.getLabel(), "service name", service.Name, "namespace", service.Namespace)
return nil
case watch.Error:
errObject := apierrors.FromObject(event.Object)
statusErr, _ := errObject.(*apierrors.StatusError)
log.Errorf("[%s] -> %v", provider.getLabel(), statusErr)
log.Error("watch error", "provider", provider.getLabel(), "err", statusErr)
}
}
close(exitFunction)
log.Infof("[%s] stopping watching for [%s] in namespace [%s]", provider.getLabel(), service.Name, service.Namespace)
log.Info("stopping watching", "provider", provider.getLabel(), "service name", service.Name, "namespace", service.Namespace)
return nil //nolint:govet
}
@@ -450,11 +451,11 @@ func (sm *Manager) clearRoutes(service *v1.Service) []error {
if sm.countRouteReferences(route) <= 1 {
err := cluster.Network[i].DeleteRoute()
if err != nil && !errors.Is(err, syscall.ESRCH) {
log.Errorf("failed to delete route for %s: %s", cluster.Network[i].IP(), err.Error())
log.Error("failed to delete route", "ip", cluster.Network[i].IP(), "err", err)
errs = append(errs, err)
}
log.Debugf("deleted route: %s, service: %s/%s, interface: %s, table: %d",
cluster.Network[i].IP(), service.Namespace, service.Name, cluster.Network[i].Interface(), sm.config.RoutingTableID)
log.Debug("deleted route", "ip",
cluster.Network[i].IP(), "service name", service.Name, "namespace", service.Namespace, "interface", cluster.Network[i].Interface(), "tableID", sm.config.RoutingTableID)
}
}
}
@@ -469,10 +470,10 @@ func (sm *Manager) clearBGPHosts(service *v1.Service) {
address := fmt.Sprintf("%s/%s", cluster.Network[i].IP(), sm.config.VIPCIDR)
err := sm.bgpServer.DelHost(address)
if err != nil {
log.Errorf("[endpoint] error deleting BGP host %s\n", err.Error())
log.Error("[endpoint] error deleting BGP host", "err", err)
} else {
log.Debugf("[endpoint] deleted BGP host: %s, service: %s/%s",
address, service.Namespace, service.Name)
log.Debug("[endpoint] deleted BGP host", "ip",
address, "service name", service.Name, "namespace", service.Namespace)
}
}
}

View File

@@ -4,8 +4,9 @@ import (
"context"
"fmt"
log "log/slog"
"github.com/kube-vip/kube-vip/pkg/kubevip"
log "github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
discoveryv1 "k8s.io/api/discovery/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -67,14 +68,14 @@ func (ep *endpointslicesProvider) getLocalEndpoints(id string, _ *kubevip.Config
continue
}
for _, address := range endpoint.Addresses {
log.Debugf("[%s] processing endpoint [%s]", ep.label, address)
log.Debug("processing endpoint", "provider", ep.label, "ip", address)
// 1. Compare the Nodename
if endpoint.NodeName != nil && id == *endpoint.NodeName {
if endpoint.Hostname != nil {
log.Debugf("[%s] found endpoint - address: %s, hostname: %s, node: %s", ep.label, address, *endpoint.Hostname, *endpoint.NodeName)
log.Debug("found endpoint", "provider", ep.label, "ip", address, "hostname", *endpoint.Hostname, "nodename", *endpoint.NodeName)
} else {
log.Debugf("[%s] found endpoint - address: %s, node: %s", ep.label, address, *endpoint.NodeName)
log.Debug("found endpoint", "provider", ep.label, "ip", address, "nodename", *endpoint.NodeName)
}
localEndpoints = append(localEndpoints, address)
continue
@@ -82,7 +83,7 @@ func (ep *endpointslicesProvider) getLocalEndpoints(id string, _ *kubevip.Config
// 2. Compare the Hostname (only useful if endpoint.NodeName is not available)
if endpoint.Hostname != nil && id == *endpoint.Hostname {
log.Debugf("[%s] found endpoint - address: %s, hostname: %s", ep.label, address, *endpoint.Hostname)
log.Debug("found endpoint", "provider", ep.label, "ip", address, "hostname", *endpoint.Hostname)
localEndpoints = append(localEndpoints, address)
}
}
@@ -109,14 +110,14 @@ func (ep *endpointslicesProvider) updateServiceAnnotation(endpoint, endpointIPv6
_, err = sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{})
if err != nil {
log.Errorf("[%s] error updating Service Spec [%s] : %v", ep.label, currentServiceCopy.Name, err)
log.Error("error updating Service Spec", "provider", ep.label, "service name", currentServiceCopy.Name, "err", err)
return err
}
return nil
})
if retryErr != nil {
log.Errorf("[%s] failed to set Services: %v", ep.label, retryErr)
log.Error("failed to set Services", "provider", ep.label, "err", retryErr)
return retryErr
}
return nil

View File

@@ -6,10 +6,11 @@ import (
"reflect"
"sync"
log "log/slog"
"github.com/davecgh/go-spew/spew"
"github.com/kube-vip/kube-vip/pkg/vip"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -57,16 +58,16 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
// clean up traffic mirror related config
err := sm.stopTrafficMirroringIfEnabled()
if err != nil {
log.Fatal(err)
log.Error("Stopping traffic mirroring", "err", err)
}
}()
if sm.config.ServiceNamespace == "" {
// v1.NamespaceAll is actually "", but we'll stay with the const in case things change upstream
sm.config.ServiceNamespace = v1.NamespaceAll
log.Infof("(svcs) starting services watcher for all namespaces")
log.Info("(svcs) starting services watcher for all namespaces")
} else {
log.Infof("(svcs) starting services watcher for services in namespace [%s]", sm.config.ServiceNamespace)
log.Info("(svcs) starting services watcher", "namespace", sm.config.ServiceNamespace)
}
// Use a restartable watcher, as this should help in the event of etcd or timeout issues
@@ -115,7 +116,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
// Check if we ignore this service
if svc.Annotations["kube-vip.io/ignore"] == "true" {
log.Infof("(svcs) [%s] has an ignore annotation for kube-vip", svc.Name)
log.Info("ignore annotation for kube-vip", "service name", svc.Name)
break
}
@@ -143,10 +144,10 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
// log.Debugf("(svcs) Retreiving local addresses, to ensure that this modified address doesn't exist: %s", addr)
f, err := vip.GarbageCollect(sm.config.Interface, addr)
if err != nil {
log.Errorf("(svcs) cleaning existing address error: [%s]", err.Error())
log.Error("(svcs) cleaning existing address error", "err", err)
}
if f {
log.Warnf("(svcs) already found existing address [%s] on adapter [%s]", addr, sm.config.Interface)
log.Warn("(svcs) already found existing config", "address", addr, "adapter", sm.config.Interface)
}
}
// This service has been modified, but it was also active..
@@ -167,7 +168,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
}
err = sm.deleteService(svc.UID)
if err != nil {
log.Errorf("(svc) unable to remove existing [%s]", svc.UID)
log.Error("(svc) unable to remove", "service", svc.UID)
}
}
// in theory this should never fail
@@ -184,7 +185,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
//
if !activeService[string(svc.UID)] {
log.Debugf("(svcs) [%s] has been added/modified with addresses [%s]", svc.Name, fetchServiceAddresses(svc))
log.Debug("(svcs) has been added/modified with addresses", "service name", svc.Name, "ip", fetchServiceAddresses(svc))
wg.Add(1)
activeServiceLoadBalancer[string(svc.UID)], activeServiceLoadBalancerCancel[string(svc.UID)] = context.WithCancel(ctx)
@@ -210,7 +211,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
provider = &endpointslicesProvider{label: "endpointslices"}
}
if err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], sm.config.NodeName, svc, &wg, provider); err != nil {
log.Error(err)
log.Error(err.Error())
}
wg.Done()
}
@@ -221,7 +222,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
go func() {
err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg)
if err != nil {
log.Error(err)
log.Error(err.Error())
}
wg.Done()
}()
@@ -241,7 +242,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
provider = &endpointslicesProvider{label: "endpointslices"}
}
if err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], sm.config.NodeName, svc, &wg, provider); err != nil {
log.Error(err)
log.Error(err.Error())
}
wg.Done()
}
@@ -251,7 +252,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
go func() {
err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg)
if err != nil {
log.Error(err)
log.Error(err.Error())
}
wg.Done()
}()
@@ -263,14 +264,14 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
for {
select {
case <-activeServiceLoadBalancer[string(svc.UID)].Done():
log.Warnf("(svcs) restartable service watcher ending for [%s]", svc.UID)
log.Warn("(svcs) restartable service watcher ending", "uid", svc.UID)
return
default:
log.Infof("(svcs) restartable service watcher starting for [%s]", svc.UID)
log.Info("(svcs) restartable service watcher starting", "uid", svc.UID)
err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg)
if err != nil {
log.Error(err)
log.Error(err.Error())
}
}
}
@@ -282,7 +283,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
wg.Add(1)
err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg)
if err != nil {
log.Error(err)
log.Error(err.Error())
}
wg.Done()
}
@@ -302,7 +303,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
// We can ignore this service
if svc.Annotations["kube-vip.io/ignore"] == "true" {
log.Infof("(svcs) [%s] has an ignore annotation for kube-vip", svc.Name)
log.Info("(svcs)ignore annotation for kube-vip", "service name", svc.Name)
break
}
@@ -321,7 +322,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
// If this is an active service then and additional leaderElection will handle stopping
err = sm.deleteService(svc.UID)
if err != nil {
log.Error(err)
log.Error(err.Error())
}
// Calls the cancel function of the context
@@ -339,7 +340,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
vipCidr := fmt.Sprintf("%s/%s", vip.VIP, vip.VIPCIDR)
err = sm.bgpServer.DelHost(vipCidr)
if err != nil {
log.Errorf("error deleting host %s: %s", vipCidr, err.Error())
log.Error("error deleting host", "ip", vipCidr, "err", err)
}
}
} else {
@@ -347,7 +348,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
}
}
log.Infof("(svcs) [%s/%s] has been deleted", svc.Namespace, svc.Name)
log.Info("(svcs) deleted", "service name", svc.Name, "namespace", svc.Namespace)
case watch.Bookmark:
// Un-used
case watch.Error:
@@ -361,7 +362,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
}
status := statusErr.ErrStatus
log.Errorf("services -> %v", status)
log.Error("services", "err", status)
default:
}
}
@@ -372,18 +373,18 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context
func (sm *Manager) lbClassFilterLegacy(svc *v1.Service) bool {
if svc == nil {
log.Infof("(svcs) service is nil, ignoring")
log.Info("(svcs) service is nil, ignoring")
return true
}
if svc.Spec.LoadBalancerClass != nil {
// if this isn't nil then it has been configured, check if it the kube-vip loadBalancer class
if *svc.Spec.LoadBalancerClass != sm.config.LoadBalancerClassName {
log.Infof("(svcs) [%s] specified the loadBalancer class [%s], ignoring", svc.Name, *svc.Spec.LoadBalancerClass)
log.Info("(svcs) specified the wrong loadBalancer class", "service name", svc.Name, "lbClass", *svc.Spec.LoadBalancerClass)
return true
}
} else if sm.config.LoadBalancerClassOnly {
// if kube-vip is configured to only recognize services with kube-vip's lb class, then ignore the services without any lb class
log.Infof("(svcs) kube-vip configured to only recognize services with kube-vip's lb class but the service [%s] didn't specify any loadBalancer class, ignoring", svc.Name)
log.Info("(svcs) kube-vip configured to only recognize services with kube-vip's lb class but the service didn't specify any loadBalancer class, ignoring", "service name", svc.Name)
return true
}
return false
@@ -391,18 +392,18 @@ func (sm *Manager) lbClassFilterLegacy(svc *v1.Service) bool {
func (sm *Manager) lbClassFilter(svc *v1.Service) bool {
if svc == nil {
log.Infof("(svcs) service is nil, ignoring")
log.Info("(svcs) service is nil, ignoring")
return true
}
if svc.Spec.LoadBalancerClass == nil && sm.config.LoadBalancerClassName != "" {
log.Infof("(svcs) [%s] specified no loadBalancer class, expected [%s], ignoring", svc.Name, sm.config.LoadBalancerClassName)
log.Info("(svcs) no loadBalancer class, ignoring", "service name", svc.Name, "expected lbClass", sm.config.LoadBalancerClassName)
return true
}
if svc.Spec.LoadBalancerClass == nil && sm.config.LoadBalancerClassName == "" {
return false
}
if *svc.Spec.LoadBalancerClass != sm.config.LoadBalancerClassName {
log.Infof("(svcs) [%s] specified loadBalancer class [%s], expected [%s], ignoring", svc.Name, *svc.Spec.LoadBalancerClass, sm.config.LoadBalancerClassName)
log.Info("(svcs) specified wrong loadBalancer class, ignoring", "service name", svc.Name, "wrong lbClass", *svc.Spec.LoadBalancerClass, "expected lbClass", sm.config.LoadBalancerClassName)
return true
}
return false

View File

@@ -4,7 +4,8 @@ import (
"errors"
"fmt"
log "github.com/sirupsen/logrus"
log "log/slog"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
)
@@ -27,16 +28,15 @@ func MirrorTrafficFromNIC(fromNICName, toNICName string) error {
return fmt.Errorf("failed to find nic %s: %v", toNICName, err)
}
toNICID := toNIC.Attrs().Index
log.Debug(fmt.Sprintf("interface %s has index %d", fromNICName, fromNICID))
log.Debug(fmt.Sprintf("interface %s has index %d", toNICName, toNICID))
log.Debugf("interface %s has index %d", fromNICName, fromNICID)
log.Debugf("interface %s has index %d", toNICName, toNICID)
log.Debugf("clean up interface %s first in case it has stale qdsic", fromNICName)
log.Debug(fmt.Sprintf("clean up interface %s first in case it has stale qdsic", fromNICName))
if err := CleanupQDSICFromNIC(fromNICName); err != nil {
return err
}
log.Debugf("step 1: tc qdisc add dev %s ingress", fromNICName)
log.Debug(fmt.Sprintf("step 1: tc qdisc add dev %s ingress", fromNICName))
qdisc1 := &netlink.Ingress{
QdiscAttrs: netlink.QdiscAttrs{
LinkIndex: fromNICID,
@@ -48,7 +48,7 @@ func MirrorTrafficFromNIC(fromNICName, toNICName string) error {
return fmt.Errorf("failed to add qdisc for interface %s: %v", fromNICName, err)
}
log.Debugf("step 2: tc filter add dev %s parent ffff: protocol ip u32 match u8 0 0 action mirred egress mirror dev %s", fromNICName, toNICName)
log.Debug(fmt.Sprintf("step 2: tc filter add dev %s parent ffff: protocol ip u32 match u8 0 0 action mirred egress mirror dev %s", fromNICName, toNICName))
// add a filter to mirror traffic from index1 to index2
filter1 := &netlink.U32{
FilterAttrs: netlink.FilterAttrs{
@@ -71,7 +71,7 @@ func MirrorTrafficFromNIC(fromNICName, toNICName string) error {
return fmt.Errorf("failed to add filter for interface %s: %v", fromNICName, err)
}
log.Debugf("step 3: tc qdisc add dev %s ingress", fromNICName)
log.Debug(fmt.Sprintf("step 3: tc qdisc add dev %s ingress", fromNICName))
qdiscTemp := netlink.NewPrio(netlink.QdiscAttrs{
LinkIndex: fromNICID,
Parent: netlink.HANDLE_ROOT,
@@ -90,7 +90,7 @@ func MirrorTrafficFromNIC(fromNICName, toNICName string) error {
return err
}
log.Debugf("step 4: tc filter add dev %s parent %d: protocol ip u32 match u8 0 0 action mirred egress mirror dev %s", fromNICName, qdiscID, toNICName)
log.Debug(fmt.Sprintf("step 4: tc filter add dev %s parent %d: protocol ip u32 match u8 0 0 action mirred egress mirror dev %s", fromNICName, qdiscID, toNICName))
filter2 := &netlink.U32{
FilterAttrs: netlink.FilterAttrs{
@@ -113,7 +113,7 @@ func MirrorTrafficFromNIC(fromNICName, toNICName string) error {
return fmt.Errorf("failed to add filter for interface %s: %v", fromNICName, err)
}
log.Infof("traffic mirroring has been set up from interface %s to interface %s", toNICName, fromNICName)
log.Info("traffic mirroring has been set up", "src", toNICName, "dst", fromNICName)
return nil
}
@@ -126,7 +126,7 @@ func CleanupQDSICFromNIC(nicName string) error {
}
nicID := toNIC.Attrs().Index
log.Debugf("interface %s has index %d", nicName, nicID)
log.Debug(fmt.Sprintf("interface %s has index %d", nicName, nicID))
log.Debug("step 1: delete ingress qdisc")
if err := tryCleanupQdiscByType(nicID, nicName, "ingress"); err != nil {
@@ -138,7 +138,7 @@ func CleanupQDSICFromNIC(nicName string) error {
return err
}
log.Infof("finished cleaning up all qdisc config on interface %s", nicName)
log.Info("finished cleaning up all qdisc config", "interface", nicName)
return nil
}
@@ -154,7 +154,7 @@ func getQdiscFromInterfaceByType(nicID int, nicName string, qType string) (uint3
return q.Attrs().Handle, nil
}
}
log.Errorf("no qdisc under interface %s is %s type", nicName, qType)
log.Error("no qdisc", "interface", nicName, "is of type", qType)
return 0, errQdiscNotFound
}
@@ -178,7 +178,7 @@ func tryCleanupQdiscByType(nicID int, nicName, qType string) error {
_, err := getQdiscFromInterfaceByType(nicID, nicName, qType)
if err != nil {
if err == errQdiscNotFound {
log.Debugf("%s type qdisc doesn't exist on interface %s, skip deleting", qType, nicName)
log.Debug(fmt.Sprintf("%s type qdisc doesn't exist on interface %s, skip deleting", qType, nicName))
return nil
}
return err

View File

@@ -4,9 +4,10 @@ import (
"context"
"strings"
log "log/slog"
"github.com/huin/goupnp"
"github.com/huin/goupnp/dcps/internetgateway2"
log "github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
)
@@ -47,7 +48,7 @@ func GetGatewayClients(ctx context.Context) []Gateway {
if wanipv6clients, err := internetgateway2.NewWANIPv6FirewallControl1ClientsByURLCtx(ctx, gatewayURL); err == nil {
gatewayClients[i].WANIPv6FirewallControlClient = wanipv6clients[0]
} else {
log.Warnf("[UPNP] Unable to find WANIPv6FirewallControl1Clients for Gateway %s [%s]", gatewayURL, err.Error())
log.Warn("[UPNP] Unable to find WANIPv6FirewallControl1Clients", "Gateway", gatewayURL, "err", err)
}
}
return gatewayClients
@@ -84,7 +85,7 @@ func GetConnectionClients(ctx context.Context) []ConnectionClient {
var routers []ConnectionClient
if err := tasks.Wait(); err != nil {
log.Errorf("[UPNP] Could not finish querying UPNP connection clients [%s]", err.Error())
log.Error("[UPNP] Could not finish querying UPNP connection clients", "err", err.Error())
return routers
}
@@ -92,7 +93,7 @@ func GetConnectionClients(ctx context.Context) []ConnectionClient {
errors = append(errors, ppp1Error...)
for _, e := range errors {
log.Warnf("[UPNP] UPNP Gateway responded with an error while querying WAN Connection Client [%s]", e.Error())
log.Warn("[UPNP] UPNP Gateway responded with an error while querying WAN Connection Client", "err", e)
}
for _, c := range ip1Clients {

View File

@@ -8,8 +8,9 @@ import (
"strings"
"sync"
log "log/slog"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
@@ -343,7 +344,7 @@ func (configurator *network) addIptablesRulesToLimitTrafficPorts() error {
if err := insertCommonIPTablesRules(ipt, vip, comment); err != nil {
return fmt.Errorf("could not add common iptables rules: %w", err)
}
log.Debugf("add iptables rules, vip: %s, ports: %+v", vip, configurator.ports)
log.Debug("add iptables rules", "vip", vip, "ports", configurator.ports)
if err := configurator.insertIPTablesRulesForServicePorts(ipt, vip, comment); err != nil {
return fmt.Errorf("could not add iptables rules for service ports: %v", err)
}
@@ -448,7 +449,7 @@ func (configurator *network) removeIptablesRuleToLimitTrafficPorts() error {
return fmt.Errorf("could not delete common iptables rules: %w", err)
}
log.Debugf("remove iptables rules, vip: %s, ports: %+v", vip, configurator.ports)
log.Debug("remove iptables rules", "vip", vip, "ports", configurator.ports)
for _, port := range configurator.ports {
// iptables -D INPUT -d <VIP> -p <protocol> --dport <port> -j ACCEPT
if err := ipt.DeleteIfExists(iptables.TableFilter, iptables.ChainInput, "-d", vip, "-p", string(port.Protocol),

View File

@@ -5,8 +5,9 @@ import (
"net"
"time"
log "log/slog"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
// DDNSManager will start a dhclient to retrieve and keep the lease for the IP
@@ -55,7 +56,7 @@ func (ddns *ddnsManager) Start() (string, error) {
client.Stop()
return "", errors.New("failed to get IP from dhcp for ddns in 1 minutes")
case ip = <-client.IPChannel():
log.Info("got ip from dhcp: ", ip)
log.Info("got address from dhcp", "ip", ip)
}
// lease.FixedAddress.String() could return <nil>
@@ -74,7 +75,7 @@ func (ddns *ddnsManager) Start() (string, error) {
client.Stop()
return
case ip := <-client.IPChannel():
log.Info("got ip from dhcp: ", ip)
log.Info("got address from dhcp", "ip", ip)
}
}
}(ddns.ctx)

View File

@@ -8,10 +8,11 @@ import (
"net"
"time"
log "log/slog"
"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/dhcpv4/nclient4"
"github.com/jpillora/backoff"
log "github.com/sirupsen/logrus"
)
const dhcpClientPort = "68"
@@ -129,7 +130,7 @@ func (c *DHCPClient) Start() {
// Set up two ticker to renew/rebind regularly
t1Timeout := c.lease.ACK.IPAddressLeaseTime(defaultDHCPRenew) / 2
t2Timeout := (c.lease.ACK.IPAddressLeaseTime(defaultDHCPRenew) / 8) * 7
log.Debugf("t1 %v t2 %v", t1Timeout, t2Timeout)
log.Debug("dhcp timeouts", "timeout1", t1Timeout, "timeoute2", t2Timeout)
t1, t2 := time.NewTicker(t1Timeout), time.NewTicker(t2Timeout)
for {
@@ -143,25 +144,25 @@ func (c *DHCPClient) Start() {
lease, err := c.renew()
if err == nil {
c.lease = lease
log.Infof("renew, lease: %+v", lease)
log.Info("renew", "lease", lease)
t2.Reset(t2Timeout)
} else {
log.Errorf("renew failed, error: %s", err.Error())
log.Error("renew failed", "err", err)
}
case <-t2.C:
// rebind is just like a request, but forcing to provide a new IP address
lease, err := c.request(true)
if err == nil {
c.lease = lease
log.Infof("rebind, lease: %+v", lease)
log.Info("rebind", "lease", lease)
} else {
if _, ok := err.(*nclient4.ErrNak); !ok {
t1.Stop()
t2.Stop()
log.Errorf("rebind failed, error: %s", err.Error())
log.Error("rebind failed", "err", err)
return
}
log.Warnf("ip %s may have changed: %s", c.lease.ACK.YourIPAddr, err.Error())
log.Warn("ip may have changed", "ip", c.lease.ACK.YourIPAddr, "err", err)
c.initRebootFlag = false
c.lease = c.requestWithBackoff()
}
@@ -171,9 +172,9 @@ func (c *DHCPClient) Start() {
case <-c.stopChan:
// release is a unicast request of the IP release.
if err := c.release(); err != nil {
log.Errorf("release lease failed, error: %s, lease: %+v", err.Error(), c.lease)
log.Error("release lease failed", "lease", lease, "err", err)
} else {
log.Infof("release, lease: %+v", c.lease)
log.Info("release", "lease", lease)
}
t1.Stop()
t2.Stop()
@@ -205,18 +206,18 @@ func (c *DHCPClient) requestWithBackoff() *nclient4.Lease {
var err error
for {
log.Debugf("trying to get a new IP, attempt %f", backoff.Attempt())
log.Debug("trying to get a new IP", "attempt", backoff.Attempt())
lease, err = c.request(false)
if err != nil {
dur := backoff.Duration()
if backoff.Attempt() > maxBackoffAttempts-1 {
errMsg := fmt.Errorf("failed to get an IP address after %d attempts, error %s, giving up", maxBackoffAttempts, err.Error())
log.Error(errMsg)
log.Error(errMsg.Error())
c.errorChan <- errMsg
c.Stop()
return nil
}
log.Errorf("request failed, error: %s (waiting %v)", err.Error(), dur)
log.Error("request failed", "err", err.Error(), "waiting", dur)
time.Sleep(dur)
continue
}
@@ -225,7 +226,7 @@ func (c *DHCPClient) requestWithBackoff() *nclient4.Lease {
}
if c.ipChan != nil {
log.Debugf("using channel")
log.Debug("using channel")
c.ipChan <- lease.ACK.YourIPAddr.String()
}
@@ -251,13 +252,13 @@ func (c *DHCPClient) request(rebind bool) (*nclient4.Lease, error) {
// if initRebootFlag is set, this means we have an IP already set on c.requestedIP that should be used
if c.initRebootFlag {
log.Debugf("init-reboot ip %s", c.requestedIP)
log.Debug("init-reboot", "ip", c.requestedIP)
modifiers = append(modifiers, dhcpv4.WithOption(dhcpv4.OptRequestedIPAddress(c.requestedIP)))
}
// if this is a rebind, then the IP we should set is the one that already exists in lease
if rebind {
log.Debugf("rebinding ip %s", c.lease.ACK.YourIPAddr)
log.Debug("rebinding", "ip", c.lease.ACK.YourIPAddr)
modifiers = append(modifiers, dhcpv4.WithOption(dhcpv4.OptRequestedIPAddress(c.lease.ACK.YourIPAddr)))
}

View File

@@ -4,7 +4,7 @@ import (
"context"
"time"
log "github.com/sirupsen/logrus"
log "log/slog"
)
// IPUpdater is the interface to plug dns updaters
@@ -29,7 +29,7 @@ func (d *ipUpdater) Run(ctx context.Context) {
for {
select {
case <-ctx.Done():
log.Infof("stop ipUpdater")
log.Info("stop ipUpdater")
return
default:
mode := "ipv4"
@@ -39,18 +39,18 @@ func (d *ipUpdater) Run(ctx context.Context) {
ip, err := LookupHost(d.vip.DNSName(), mode)
if err != nil {
log.Warnf("cannot lookup %s: %v", d.vip.DNSName(), err)
log.Warn("cannot lookup", "name", d.vip.DNSName(), "err", err)
// fallback to renewing the existing IP
ip = []string{d.vip.IP()}
}
log.Infof("setting %s as an IP", ip)
log.Info("setting IP", "address", ip)
if err := d.vip.SetIP(ip[0]); err != nil {
log.Errorf("setting %s as an IP: %v", ip, err)
log.Error("setting IP", "address", ip, "err", err)
}
if err := d.vip.AddIP(false); err != nil {
log.Errorf("error adding virtual IP: %v", err)
log.Error("error adding virtual IP", "err", err)
}
}

View File

@@ -5,8 +5,9 @@ import (
"strconv"
"strings"
log "log/slog"
iptables "github.com/kube-vip/kube-vip/pkg/iptables"
log "github.com/sirupsen/logrus"
ct "github.com/florianl/go-conntrack"
)
@@ -39,7 +40,7 @@ func CreateIptablesClient(nftables bool, namespace string, protocol iptables.Pro
if protocol == iptables.ProtocolIPv6 {
proto = "IPv6"
}
log.Infof("[egress] Creating an iptables client, nftables mode [%t], protocol [%s]", nftables, proto)
log.Info("[egress] Creating an iptables client", "nftables", nftables, "protocol", proto)
e := new(Egress)
var err error
@@ -56,7 +57,7 @@ func CreateIptablesClient(nftables bool, namespace string, protocol iptables.Pro
}
func (e *Egress) CheckMangleChain(name string) (bool, error) {
log.Infof("[egress] Checking for Chain [%s]", name)
log.Info("[egress] chain exists", "name", name)
return e.ipTablesClient.ChainExists("mangle", name)
}
@@ -73,7 +74,7 @@ func (e *Egress) DeleteMangleReturnForNetwork(name, network string) error {
}
func (e *Egress) DeleteMangleMarking(podIP, name string) error {
log.Infof("[egress] Stopping marking packets on network [%s]", podIP)
log.Info("[egress] Stopping marking packets on network", "podIP", podIP)
exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", podIP, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", e.comment)
@@ -84,7 +85,7 @@ func (e *Egress) DeleteMangleMarking(podIP, name string) error {
}
func (e *Egress) DeleteMangleMarkingForNetwork(podIP, name, network string) error {
log.Infof("[egress] Stopping marking packets from [%s] to [%s]", podIP, network)
log.Info("[egress] Stopping marking packets", "podIP", podIP, "network", network)
// exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", podIP, "-d", network, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", e.comment)
@@ -95,7 +96,7 @@ func (e *Egress) DeleteMangleMarkingForNetwork(podIP, name, network string) erro
}
func (e *Egress) DeleteSourceNat(podIP, vip string) error {
log.Infof("[egress] Removing source nat from [%s] => [%s]", podIP, vip)
log.Info("[egress] Removing source nat", "podIP", podIP, "vip", vip)
exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", e.comment)
@@ -106,7 +107,7 @@ func (e *Egress) DeleteSourceNat(podIP, vip string) error {
}
func (e *Egress) DeleteSourceNatForDestinationPort(podIP, vip, port, proto string) error {
log.Infof("[egress] Removing source nat from [%s] => [%s], with destination port [%s]", podIP, vip, port)
log.Info("[egress] Removing source nat", "podIP", podIP, "vip", vip, "destination port", port)
exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", e.comment)
@@ -118,13 +119,13 @@ func (e *Egress) DeleteSourceNatForDestinationPort(podIP, vip, port, proto strin
func (e *Egress) CreateMangleChain(name string) error {
log.Infof("[egress] Creating Chain [%s]", name)
log.Info("[egress] Creating Chain", "name", name)
// Creates a new chain in the mangle table
return e.ipTablesClient.NewChain("mangle", name)
}
func (e *Egress) AppendReturnRulesForDestinationSubnet(name, subnet string) error {
log.Infof("[egress] Adding jump for subnet [%s] to RETURN to previous chain/rules", subnet)
log.Info("[egress] Adding jump for subnet to RETURN to previous chain/rules", "subnet", subnet)
exists, _ := e.ipTablesClient.Exists("mangle", name, "-d", subnet, "-j", "RETURN", "-m", "comment", "--comment", e.comment)
if !exists {
return e.ipTablesClient.Append("mangle", name, "-d", subnet, "-j", "RETURN", "-m", "comment", "--comment", e.comment)
@@ -133,7 +134,7 @@ func (e *Egress) AppendReturnRulesForDestinationSubnet(name, subnet string) erro
}
func (e *Egress) AppendReturnRulesForMarking(name, subnet string) error {
log.Infof("[egress] Marking packets on network [%s]", subnet)
log.Info("[egress] Marking packets on network", "subnet", subnet)
exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", e.comment)
if !exists {
return e.ipTablesClient.Append("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", e.comment)
@@ -142,7 +143,7 @@ func (e *Egress) AppendReturnRulesForMarking(name, subnet string) error {
}
func (e *Egress) AppendReturnRulesForMarkingForNetwork(name, subnet, destination string) error {
log.Infof("[egress] Marking packets on network [%s]", subnet)
log.Info("[egress] Marking packets on network", "subnet", subnet)
exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", subnet, "-d", destination, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", e.comment)
if !exists {
return e.ipTablesClient.Append("mangle", name, "-s", subnet, "-d", destination, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", e.comment)
@@ -151,7 +152,7 @@ func (e *Egress) AppendReturnRulesForMarkingForNetwork(name, subnet, destination
}
func (e *Egress) InsertMangeTableIntoPrerouting(name string) error {
log.Infof("[egress] Adding jump from mangle prerouting to [%s]", name)
log.Info("[egress] Adding jump from mangle prerouting", "destination", name)
if exists, err := e.ipTablesClient.Exists("mangle", "PREROUTING", "-j", name, "-m", "comment", "--comment", e.comment); err != nil {
return err
} else if exists {
@@ -164,7 +165,7 @@ func (e *Egress) InsertMangeTableIntoPrerouting(name string) error {
}
func (e *Egress) InsertSourceNat(vip, podIP string) error {
log.Infof("[egress] Adding source nat from [%s] => [%s]", podIP, vip)
log.Info("[egress] Adding source nat", "original source", podIP, "new source", vip)
if exists, err := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", e.comment); err != nil {
return err
} else if exists {
@@ -177,17 +178,17 @@ func (e *Egress) InsertSourceNat(vip, podIP string) error {
}
func (e *Egress) InsertSourceNatForDestinationPort(vip, podIP, port, proto string) error {
log.Infof("[egress] Adding source nat from [%s] => [%s], with destination port [%s]", podIP, vip, port)
log.Info("[egress] Adding source nat", "from", podIP, "to", vip, "port", port)
natRules, err := e.ipTablesClient.List("nat", "POSTROUTING")
if err != nil {
return err
}
foundNatRules := e.findExistingVIP(natRules, vip)
log.Warnf("[egress] Cleaning [%d] existing postrouting nat rules for vip [%s]", len(foundNatRules), vip)
log.Warn("[egress] Cleaning existing postrouting nat rules for vip", "rulecount", len(foundNatRules), "vip", vip)
for x := range foundNatRules {
err = e.ipTablesClient.Delete("nat", "POSTROUTING", foundNatRules[x][2:]...)
if err != nil {
log.Errorf("[egress] Error removing rule [%v]", err)
log.Error("[egress] removing rule", "err", err)
}
}
@@ -206,13 +207,13 @@ func DeleteExistingSessions(sessionIP string, destination bool, destinationPorts
nfct, err := ct.Open(&ct.Config{})
if err != nil {
log.Errorf("could not create nfct: %v", err)
log.Error("create conntrack client", "err", err)
return err
}
defer nfct.Close()
sessions, err := nfct.Dump(ct.Conntrack, ct.IPv4)
if err != nil {
log.Errorf("could not dump sessions: %v", err)
log.Error("could not dump sessions", "err", err)
return err
}
destPortProtocol := make(map[uint16]uint8)
@@ -239,7 +240,7 @@ func DeleteExistingSessions(sessionIP string, destination bool, destinationPorts
case strings.ToLower("sctp"):
destPortProtocol[uint16(port)] = ProtocolSCTP
default:
log.Errorf("[egress] annotation protocol [%s] isn't supported", data[0])
log.Error("[egress] annotation protocol isn't supported", "protocol ID", data[0])
}
}
}
@@ -265,7 +266,7 @@ func DeleteExistingSessions(sessionIP string, destination bool, destinationPorts
case strings.ToLower("sctp"):
srcPortProtocol[uint16(port)] = ProtocolSCTP
default:
log.Errorf("[egress] annotation protocol [%s] isn't supported", data[0])
log.Error("[egress] annotation protocol isn't supported", "protocol ID", data[0])
}
}
}
@@ -278,14 +279,14 @@ func DeleteExistingSessions(sessionIP string, destination bool, destinationPorts
if destinationPorts != "" {
proto := destPortProtocol[*session.Origin.Proto.DstPort]
if proto == *session.Origin.Proto.Number {
log.Infof("[egress] cleaning existing connection Source [%s] -> [%s:%d] proto: [%d] ", session.Origin.Src.String(), session.Origin.Dst.String(), *session.Origin.Proto.DstPort, *session.Origin.Proto.Number)
log.Info("[egress] cleaning existing connection", "src", session.Origin.Src.String(), "dst", session.Origin.Dst.String(), "dst port", *session.Origin.Proto.DstPort, "protocol", *session.Origin.Proto.Number)
err = nfct.Delete(ct.Conntrack, ct.IPv4, session)
}
} else {
err = nfct.Delete(ct.Conntrack, ct.IPv4, session)
}
if err != nil {
log.Errorf("could not delete sessions: %v", err)
log.Error("could not delete sessions", "err", err)
}
}
}
@@ -298,14 +299,14 @@ func DeleteExistingSessions(sessionIP string, destination bool, destinationPorts
if srcPorts != "" {
proto := srcPortProtocol[*session.Origin.Proto.DstPort]
if proto == *session.Origin.Proto.Number {
log.Infof("[egress] cleaning existing connection Source [%s] -> [%s:%d] proto: [%d] ", session.Origin.Src.String(), session.Origin.Dst.String(), *session.Origin.Proto.DstPort, *session.Origin.Proto.Number)
log.Info("[egress] cleaning existing connection", "src", session.Origin.Src.String(), "dst", session.Origin.Dst.String(), "dst port", *session.Origin.Proto.DstPort, "protocol", *session.Origin.Proto.Number)
err = nfct.Delete(ct.Conntrack, ct.IPv4, session)
}
} else {
err = nfct.Delete(ct.Conntrack, ct.IPv4, session)
}
if err != nil {
log.Errorf("could not delete sessions: %v", err)
log.Error("could not delete sessions", "err", err)
}
}
}
@@ -317,13 +318,13 @@ func DeleteExistingSessions(sessionIP string, destination bool, destinationPorts
// Debug functions
func (e *Egress) DumpChain(name string) error {
log.Infof("Dumping chain [%s]", name)
log.Info("Dumping chain", "name", name)
c, err := e.ipTablesClient.List("mangle", name)
if err != nil {
return err
}
for x := range c {
log.Infof("Rule -> %s", c[x])
log.Info("", "rule", c[x])
}
return nil
}
@@ -334,16 +335,16 @@ func (e *Egress) CleanIPtables() error {
return err
}
foundNatRules := e.findRules(natRules)
log.Warnf("[egress] Cleaning [%d] dangling postrouting nat rules", len(foundNatRules))
log.Warn("[egress] Cleaning dangling postrouting nat rules", "rulecount", len(foundNatRules))
for x := range foundNatRules {
err = e.ipTablesClient.Delete("nat", "POSTROUTING", foundNatRules[x][2:]...)
if err != nil {
log.Errorf("[egress] Error removing rule [%v]", err)
log.Error("[egress] Error removing rule", "err", err)
}
}
exists, err := e.CheckMangleChain(MangleChainName)
if err != nil {
log.Debugf("[egress] No Mangle chain exists [%v]", err)
log.Debug("[egress] No Mangle chain exists", "err", err)
}
if exists {
mangleRules, err := e.ipTablesClient.List("mangle", MangleChainName)
@@ -351,11 +352,11 @@ func (e *Egress) CleanIPtables() error {
return err
}
foundNatRules = e.findRules(mangleRules)
log.Warnf("[egress] Cleaning [%d] dangling prerouting mangle rules", len(foundNatRules))
log.Warn("[egress] Cleaning dangling prerouting mangle rules", "rulecount", len(foundNatRules))
for x := range foundNatRules {
err = e.ipTablesClient.Delete("mangle", MangleChainName, foundNatRules[x][2:]...)
if err != nil {
log.Errorf("[egress] Error removing rule [%v]", err)
log.Error("[egress] Error removing rule", "err", err)
}
}
@@ -367,7 +368,7 @@ func (e *Egress) CleanIPtables() error {
// log.Errorf("[egress] Error removing flushing table [%v]", err)
// }
} else {
log.Warnf("No existing mangle chain [%s] exists", MangleChainName)
log.Warn("No existing mangle chain exists", "chain name", MangleChainName)
}
return nil
}
@@ -408,13 +409,13 @@ func (e *Egress) findExistingVIP(rules []string, vip string) [][]string {
func ClearIPTables(useNftables bool, namespace string, protocol iptables.Protocol) {
i, err := CreateIptablesClient(useNftables, namespace, protocol)
if err != nil {
log.Warnf("[egress] Unable to clean any dangling egress rules [%v]", err)
log.Warn("[egress] Unable to clean any dangling egress rules", "err", err)
log.Warn("[egress] Can be ignored in non iptables release of kube-vip")
} else {
log.Info("[egress] Cleaning any dangling kube-vip egress rules")
cleanErr := i.CleanIPtables()
if cleanErr != nil {
log.Errorf("Error cleaning rules [%v]", cleanErr)
log.Error("Error cleaning rules", "err", cleanErr)
}
}
}

View File

@@ -7,7 +7,7 @@ import (
"github.com/mdlayher/ndp"
log "github.com/sirupsen/logrus"
log "log/slog"
)
// NdpResponder defines the parameters for the NDP connection.
@@ -50,7 +50,7 @@ func (n *NdpResponder) SendGratuitous(address string) error {
return fmt.Errorf("failed to parse address %s", ip)
}
log.Infof("Broadcasting NDP update for %s (%s) via %s", address, n.hardwareAddr, n.intf)
log.Info("Broadcasting NDP update", "ip", address, "hwaddr", n.hardwareAddr, "interface", n.intf)
return n.advertise(netip.IPv6LinkLocalAllNodes(), ip, true)
}
@@ -66,6 +66,6 @@ func (n *NdpResponder) advertise(dst, target netip.Addr, gratuitous bool) error
},
},
}
log.Infof("ndp: %v", m)
log.Debug("ndp", "advertisement", m)
return n.conn.WriteTo(m, nil, dst)
}

View File

@@ -8,8 +8,9 @@ import (
"strings"
"syscall"
log "log/slog"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
)
@@ -167,7 +168,7 @@ func MonitorDefaultInterface(ctx context.Context, defaultIF *net.Interface) erro
for {
select {
case r := <-routeCh:
log.Debugf("type: %d, route: %+v", r.Type, r.Route)
log.Debug(fmt.Sprintf("type: %d, route: %+v", r.Type, r.Route))
if r.Type == syscall.RTM_DELROUTE && (r.Dst == nil || r.Dst.String() == "0.0.0.0/0") && r.LinkIndex == defaultIF.Index {
return fmt.Errorf("default route deleted and the default interface may be invalid")
}
@@ -191,7 +192,7 @@ func GenerateMac() (mac string) {
* - https://macaddress.io/database-download
*/
mac = fmt.Sprintf("%s:%s:%s:%02x:%02x:%02x", "00", "00", "6C", buf[0], buf[1], buf[2])
log.Infof("Generated mac: %s", mac)
log.Info("Generated mac", "address", mac)
return mac
}

View File

@@ -9,7 +9,7 @@ import (
"strings"
"time"
log "github.com/sirupsen/logrus"
log "log/slog"
)
func main() {